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());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 addxtype : function(tree,cntr)
164 cn = Roo.factory(tree);
165 //Roo.log(['addxtype', cn]);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr, is_body);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
234 addxtypeChild : function (tree, cntr, is_body)
236 Roo.debug && Roo.log('addxtypeChild:' + cntr);
238 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
241 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
242 (typeof(tree['flexy:foreach']) != 'undefined');
246 skip_children = false;
247 // render the element if it's not BODY.
250 // if parent was disabled, then do not try and create the children..
251 if(!this[cntr](true)){
256 cn = Roo.factory(tree);
258 cn.parentType = this.xtype; //??
259 cn.parentId = this.id;
261 var build_from_html = Roo.XComponent.build_from_html;
264 // does the container contain child eleemnts with 'xtype' attributes.
265 // that match this xtype..
266 // note - when we render we create these as well..
267 // so we should check to see if body has xtype set.
268 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
270 var self_cntr_el = Roo.get(this[cntr](false));
271 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
273 //Roo.log(Roo.XComponent.build_from_html);
274 //Roo.log("got echild:");
277 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
278 // and are not displayed -this causes this to use up the wrong element when matching.
279 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
282 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
283 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
289 //echild.dom.removeAttribute('xtype');
291 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
292 Roo.debug && Roo.log(self_cntr_el);
293 Roo.debug && Roo.log(echild);
294 Roo.debug && Roo.log(cn);
300 // if object has flexy:if - then it may or may not be rendered.
301 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
302 // skip a flexy if element.
303 Roo.debug && Roo.log('skipping render');
304 Roo.debug && Roo.log(tree);
306 Roo.debug && Roo.log('skipping all children');
307 skip_children = true;
312 // actually if flexy:foreach is found, we really want to create
313 // multiple copies here...
315 //Roo.log(this[cntr]());
316 // some elements do not have render methods.. like the layouts...
318 if(this[cntr](true) === false){
323 cn.render && cn.render(this[cntr](true));
326 // then add the element..
333 if (typeof (tree.menu) != 'undefined') {
334 tree.menu.parentType = cn.xtype;
335 tree.menu.triggerEl = cn.el;
336 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
340 if (!tree.items || !tree.items.length) {
342 //Roo.log(["no children", this]);
347 var items = tree.items;
350 //Roo.log(items.length);
352 if (!skip_children) {
353 for(var i =0;i < items.length;i++) {
354 // Roo.log(['add child', items[i]]);
355 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
361 //Roo.log("fire childrenrendered");
363 cn.fireEvent('childrenrendered', this);
368 * Show a component - removes 'hidden' class
376 this.getEl().removeClass('hidden');
378 if(!this.hideParent){
382 this.parent().getEl().removeClass('hidden');
386 * Hide a component - adds 'hidden' class
390 if(!this.getEl() || this.getEl().hasClass('hidden')){
394 this.getEl().addClass('hidden');
396 if(!this.hideParent){
400 this.parent().getEl().addClass('hidden');
413 * @class Roo.bootstrap.Body
414 * @extends Roo.bootstrap.Component
415 * Bootstrap Body class
419 * @param {Object} config The config object
422 Roo.bootstrap.Body = function(config){
424 config = config || {};
426 Roo.bootstrap.Body.superclass.constructor.call(this, config);
427 this.el = Roo.get(config.el ? config.el : document.body );
428 if (this.cls && this.cls.length) {
429 Roo.get(document.body).addClass(this.cls);
433 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
435 is_body : true,// just to make sure it's constructed?
440 onRender : function(ct, position)
442 /* Roo.log("Roo.bootstrap.Body - onRender");
443 if (this.cls && this.cls.length) {
444 Roo.get(document.body).addClass(this.cls);
463 * @class Roo.bootstrap.ButtonGroup
464 * @extends Roo.bootstrap.Component
465 * Bootstrap ButtonGroup class
466 * @cfg {String} size lg | sm | xs (default empty normal)
467 * @cfg {String} align vertical | justified (default none)
468 * @cfg {String} direction up | down (default down)
469 * @cfg {Boolean} toolbar false | true
470 * @cfg {Boolean} btn true | false
475 * @param {Object} config The config object
478 Roo.bootstrap.ButtonGroup = function(config){
479 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
482 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
490 getAutoCreate : function(){
496 cfg.html = this.html || cfg.html;
507 if (['vertical','justified'].indexOf(this.align)!==-1) {
508 cfg.cls = 'btn-group-' + this.align;
510 if (this.align == 'justified') {
511 console.log(this.items);
515 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
516 cfg.cls += ' btn-group-' + this.size;
519 if (this.direction == 'up') {
520 cfg.cls += ' dropup' ;
536 * @class Roo.bootstrap.Button
537 * @extends Roo.bootstrap.Component
538 * Bootstrap Button class
539 * @cfg {String} html The button content
540 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
541 * @cfg {String} size ( lg | sm | xs)
542 * @cfg {String} tag ( a | input | submit)
543 * @cfg {String} href empty or href
544 * @cfg {Boolean} disabled default false;
545 * @cfg {Boolean} isClose default false;
546 * @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)
547 * @cfg {String} badge text for badge
548 * @cfg {String} theme default
549 * @cfg {Boolean} inverse
550 * @cfg {Boolean} toggle
551 * @cfg {String} ontext text for on toggle state
552 * @cfg {String} offtext text for off toggle state
553 * @cfg {Boolean} defaulton
554 * @cfg {Boolean} preventDefault default true
555 * @cfg {Boolean} removeClass remove the standard class..
556 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
559 * Create a new button
560 * @param {Object} config The config object
564 Roo.bootstrap.Button = function(config){
565 Roo.bootstrap.Button.superclass.constructor.call(this, config);
566 this.weightClass = ["btn-default",
578 * When a butotn is pressed
579 * @param {Roo.bootstrap.Button} this
580 * @param {Roo.EventObject} e
585 * After the button has been toggles
586 * @param {Roo.EventObject} e
587 * @param {boolean} pressed (also available as button.pressed)
593 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
611 preventDefault: true,
620 getAutoCreate : function(){
628 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
629 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
634 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
636 if (this.toggle == true) {
639 cls: 'slider-frame roo-button',
644 'data-off-text':'OFF',
645 cls: 'slider-button',
651 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
652 cfg.cls += ' '+this.weight;
661 cfg["aria-hidden"] = true;
663 cfg.html = "×";
669 if (this.theme==='default') {
670 cfg.cls = 'btn roo-button';
672 //if (this.parentType != 'Navbar') {
673 this.weight = this.weight.length ? this.weight : 'default';
675 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
677 cfg.cls += ' btn-' + this.weight;
679 } else if (this.theme==='glow') {
682 cfg.cls = 'btn-glow roo-button';
684 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
686 cfg.cls += ' ' + this.weight;
692 this.cls += ' inverse';
697 cfg.cls += ' active';
701 cfg.disabled = 'disabled';
705 Roo.log('changing to ul' );
707 this.glyphicon = 'caret';
710 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
712 //gsRoo.log(this.parentType);
713 if (this.parentType === 'Navbar' && !this.parent().bar) {
714 Roo.log('changing to li?');
723 href : this.href || '#'
726 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
727 cfg.cls += ' dropdown';
734 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
736 if (this.glyphicon) {
737 cfg.html = ' ' + cfg.html;
742 cls: 'glyphicon glyphicon-' + this.glyphicon
752 // cfg.cls='btn roo-button';
756 var value = cfg.html;
761 cls: 'glyphicon glyphicon-' + this.glyphicon,
780 cfg.cls += ' dropdown';
781 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
784 if (cfg.tag !== 'a' && this.href !== '') {
785 throw "Tag must be a to set href.";
786 } else if (this.href.length > 0) {
787 cfg.href = this.href;
790 if(this.removeClass){
795 cfg.target = this.target;
800 initEvents: function() {
801 // Roo.log('init events?');
802 // Roo.log(this.el.dom);
805 if (typeof (this.menu) != 'undefined') {
806 this.menu.parentType = this.xtype;
807 this.menu.triggerEl = this.el;
808 this.addxtype(Roo.apply({}, this.menu));
812 if (this.el.hasClass('roo-button')) {
813 this.el.on('click', this.onClick, this);
815 this.el.select('.roo-button').on('click', this.onClick, this);
818 if(this.removeClass){
819 this.el.on('click', this.onClick, this);
822 this.el.enableDisplayMode();
825 onClick : function(e)
832 Roo.log('button on click ');
833 if(this.preventDefault){
836 if (this.pressed === true || this.pressed === false) {
837 this.pressed = !this.pressed;
838 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
839 this.fireEvent('toggle', this, e, this.pressed);
843 this.fireEvent('click', this, e);
847 * Enables this button
851 this.disabled = false;
852 this.el.removeClass('disabled');
856 * Disable this button
860 this.disabled = true;
861 this.el.addClass('disabled');
864 * sets the active state on/off,
865 * @param {Boolean} state (optional) Force a particular state
867 setActive : function(v) {
869 this.el[v ? 'addClass' : 'removeClass']('active');
872 * toggles the current active state
874 toggleActive : function()
876 var active = this.el.hasClass('active');
877 this.setActive(!active);
881 setText : function(str)
883 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
887 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
898 setWeight : function(str)
900 this.el.removeClass(this.weightClass);
901 this.el.addClass('btn-' + str);
915 * @class Roo.bootstrap.Column
916 * @extends Roo.bootstrap.Component
917 * Bootstrap Column class
918 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
919 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
920 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
921 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
922 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
923 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
924 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
925 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
928 * @cfg {Boolean} hidden (true|false) hide the element
929 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
930 * @cfg {String} fa (ban|check|...) font awesome icon
931 * @cfg {Number} fasize (1|2|....) font awsome size
933 * @cfg {String} icon (info-sign|check|...) glyphicon name
935 * @cfg {String} html content of column.
938 * Create a new Column
939 * @param {Object} config The config object
942 Roo.bootstrap.Column = function(config){
943 Roo.bootstrap.Column.superclass.constructor.call(this, config);
946 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
964 getAutoCreate : function(){
965 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
973 ['xs','sm','md','lg'].map(function(size){
974 //Roo.log( size + ':' + settings[size]);
976 if (settings[size+'off'] !== false) {
977 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
980 if (settings[size] === false) {
984 if (!settings[size]) { // 0 = hidden
985 cfg.cls += ' hidden-' + size;
988 cfg.cls += ' col-' + size + '-' + settings[size];
993 cfg.cls += ' hidden';
996 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
997 cfg.cls +=' alert alert-' + this.alert;
1001 if (this.html.length) {
1002 cfg.html = this.html;
1006 if (this.fasize > 1) {
1007 fasize = ' fa-' + this.fasize + 'x';
1009 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1014 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1033 * @class Roo.bootstrap.Container
1034 * @extends Roo.bootstrap.Component
1035 * Bootstrap Container class
1036 * @cfg {Boolean} jumbotron is it a jumbotron element
1037 * @cfg {String} html content of element
1038 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1039 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1040 * @cfg {String} header content of header (for panel)
1041 * @cfg {String} footer content of footer (for panel)
1042 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1043 * @cfg {String} tag (header|aside|section) type of HTML tag.
1044 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1045 * @cfg {String} fa font awesome icon
1046 * @cfg {String} icon (info-sign|check|...) glyphicon name
1047 * @cfg {Boolean} hidden (true|false) hide the element
1048 * @cfg {Boolean} expandable (true|false) default false
1049 * @cfg {Boolean} expanded (true|false) default true
1050 * @cfg {String} rheader contet on the right of header
1051 * @cfg {Boolean} clickable (true|false) default false
1055 * Create a new Container
1056 * @param {Object} config The config object
1059 Roo.bootstrap.Container = function(config){
1060 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1066 * After the panel has been expand
1068 * @param {Roo.bootstrap.Container} this
1073 * After the panel has been collapsed
1075 * @param {Roo.bootstrap.Container} this
1080 * When a element is chick
1081 * @param {Roo.bootstrap.Container} this
1082 * @param {Roo.EventObject} e
1088 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1106 getChildContainer : function() {
1112 if (this.panel.length) {
1113 return this.el.select('.panel-body',true).first();
1120 getAutoCreate : function(){
1123 tag : this.tag || 'div',
1127 if (this.jumbotron) {
1128 cfg.cls = 'jumbotron';
1133 // - this is applied by the parent..
1135 // cfg.cls = this.cls + '';
1138 if (this.sticky.length) {
1140 var bd = Roo.get(document.body);
1141 if (!bd.hasClass('bootstrap-sticky')) {
1142 bd.addClass('bootstrap-sticky');
1143 Roo.select('html',true).setStyle('height', '100%');
1146 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1150 if (this.well.length) {
1151 switch (this.well) {
1154 cfg.cls +=' well well-' +this.well;
1163 cfg.cls += ' hidden';
1167 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1168 cfg.cls +=' alert alert-' + this.alert;
1173 if (this.panel.length) {
1174 cfg.cls += ' panel panel-' + this.panel;
1176 if (this.header.length) {
1180 if(this.expandable){
1182 cfg.cls = cfg.cls + ' expandable';
1186 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1194 cls : 'panel-title',
1195 html : (this.expandable ? ' ' : '') + this.header
1199 cls: 'panel-header-right',
1205 cls : 'panel-heading',
1206 style : this.expandable ? 'cursor: pointer' : '',
1214 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1219 if (this.footer.length) {
1221 cls : 'panel-footer',
1230 body.html = this.html || cfg.html;
1231 // prefix with the icons..
1233 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1236 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1241 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1242 cfg.cls = 'container';
1248 initEvents: function()
1250 if(this.expandable){
1251 var headerEl = this.headerEl();
1254 headerEl.on('click', this.onToggleClick, this);
1259 this.el.on('click', this.onClick, this);
1264 onToggleClick : function()
1266 var headerEl = this.headerEl();
1282 if(this.fireEvent('expand', this)) {
1284 this.expanded = true;
1286 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1288 this.el.select('.panel-body',true).first().removeClass('hide');
1290 var toggleEl = this.toggleEl();
1296 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1301 collapse : function()
1303 if(this.fireEvent('collapse', this)) {
1305 this.expanded = false;
1307 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1308 this.el.select('.panel-body',true).first().addClass('hide');
1310 var toggleEl = this.toggleEl();
1316 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1320 toggleEl : function()
1322 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1326 return this.el.select('.panel-heading .fa',true).first();
1329 headerEl : function()
1331 if(!this.el || !this.panel.length || !this.header.length){
1335 return this.el.select('.panel-heading',true).first()
1340 if(!this.el || !this.panel.length){
1344 return this.el.select('.panel-body',true).first()
1347 titleEl : function()
1349 if(!this.el || !this.panel.length || !this.header.length){
1353 return this.el.select('.panel-title',true).first();
1356 setTitle : function(v)
1358 var titleEl = this.titleEl();
1364 titleEl.dom.innerHTML = v;
1367 getTitle : function()
1370 var titleEl = this.titleEl();
1376 return titleEl.dom.innerHTML;
1379 setRightTitle : function(v)
1381 var t = this.el.select('.panel-header-right',true).first();
1387 t.dom.innerHTML = v;
1390 onClick : function(e)
1394 this.fireEvent('click', this, e);
1397 allChildren : function()
1399 var r=new Roo.util.MixedCollection(false, function(o){
1400 return o.id || (o.id = Roo.id());
1402 var iter = function(el) {
1409 Roo.each(el.items,function(e) {
1418 checkEmpty : function()
1420 var items = this.allChildren();
1423 items.each(function(f){
1424 if(f.el.isVisible()) {
1443 * @class Roo.bootstrap.Img
1444 * @extends Roo.bootstrap.Component
1445 * Bootstrap Img class
1446 * @cfg {Boolean} imgResponsive false | true
1447 * @cfg {String} border rounded | circle | thumbnail
1448 * @cfg {String} src image source
1449 * @cfg {String} alt image alternative text
1450 * @cfg {String} href a tag href
1451 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1452 * @cfg {String} xsUrl xs image source
1453 * @cfg {String} smUrl sm image source
1454 * @cfg {String} mdUrl md image source
1455 * @cfg {String} lgUrl lg image source
1458 * Create a new Input
1459 * @param {Object} config The config object
1462 Roo.bootstrap.Img = function(config){
1463 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1469 * The img click event for the img.
1470 * @param {Roo.EventObject} e
1476 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1478 imgResponsive: true,
1488 getAutoCreate : function()
1490 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1491 return this.createSingleImg();
1496 cls: 'roo-image-responsive-group',
1501 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1503 if(!_this[size + 'Url']){
1509 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1510 html: _this.html || cfg.html,
1511 src: _this[size + 'Url']
1514 img.cls += ' roo-image-responsive-' + size;
1516 var s = ['xs', 'sm', 'md', 'lg'];
1518 s.splice(s.indexOf(size), 1);
1520 Roo.each(s, function(ss){
1521 img.cls += ' hidden-' + ss;
1524 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1525 cfg.cls += ' img-' + _this.border;
1529 cfg.alt = _this.alt;
1542 a.target = _this.target;
1546 cfg.cn.push((_this.href) ? a : img);
1553 createSingleImg : function()
1557 cls: (this.imgResponsive) ? 'img-responsive' : '',
1559 src : 'about:blank' // just incase src get's set to undefined?!?
1562 cfg.html = this.html || cfg.html;
1564 cfg.src = this.src || cfg.src;
1566 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1567 cfg.cls += ' img-' + this.border;
1584 a.target = this.target;
1589 return (this.href) ? a : cfg;
1592 initEvents: function()
1595 this.el.on('click', this.onClick, this);
1600 onClick : function(e)
1602 Roo.log('img onclick');
1603 this.fireEvent('click', this, e);
1606 * Sets the url of the image - used to update it
1607 * @param {String} url the url of the image
1610 setSrc : function(url)
1614 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1615 this.el.dom.src = url;
1619 this.el.select('img', true).first().dom.src = url;
1635 * @class Roo.bootstrap.Link
1636 * @extends Roo.bootstrap.Component
1637 * Bootstrap Link Class
1638 * @cfg {String} alt image alternative text
1639 * @cfg {String} href a tag href
1640 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1641 * @cfg {String} html the content of the link.
1642 * @cfg {String} anchor name for the anchor link
1643 * @cfg {String} fa - favicon
1645 * @cfg {Boolean} preventDefault (true | false) default false
1649 * Create a new Input
1650 * @param {Object} config The config object
1653 Roo.bootstrap.Link = function(config){
1654 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1660 * The img click event for the img.
1661 * @param {Roo.EventObject} e
1667 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1671 preventDefault: false,
1677 getAutoCreate : function()
1679 var html = this.html || '';
1681 if (this.fa !== false) {
1682 html = '<i class="fa fa-' + this.fa + '"></i>';
1687 // anchor's do not require html/href...
1688 if (this.anchor === false) {
1690 cfg.href = this.href || '#';
1692 cfg.name = this.anchor;
1693 if (this.html !== false || this.fa !== false) {
1696 if (this.href !== false) {
1697 cfg.href = this.href;
1701 if(this.alt !== false){
1706 if(this.target !== false) {
1707 cfg.target = this.target;
1713 initEvents: function() {
1715 if(!this.href || this.preventDefault){
1716 this.el.on('click', this.onClick, this);
1720 onClick : function(e)
1722 if(this.preventDefault){
1725 //Roo.log('img onclick');
1726 this.fireEvent('click', this, e);
1739 * @class Roo.bootstrap.Header
1740 * @extends Roo.bootstrap.Component
1741 * Bootstrap Header class
1742 * @cfg {String} html content of header
1743 * @cfg {Number} level (1|2|3|4|5|6) default 1
1746 * Create a new Header
1747 * @param {Object} config The config object
1751 Roo.bootstrap.Header = function(config){
1752 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1755 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1763 getAutoCreate : function(){
1768 tag: 'h' + (1 *this.level),
1769 html: this.html || ''
1781 * Ext JS Library 1.1.1
1782 * Copyright(c) 2006-2007, Ext JS, LLC.
1784 * Originally Released Under LGPL - original licence link has changed is not relivant.
1787 * <script type="text/javascript">
1791 * @class Roo.bootstrap.MenuMgr
1792 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1795 Roo.bootstrap.MenuMgr = function(){
1796 var menus, active, groups = {}, attached = false, lastShow = new Date();
1798 // private - called when first menu is created
1801 active = new Roo.util.MixedCollection();
1802 Roo.get(document).addKeyListener(27, function(){
1803 if(active.length > 0){
1811 if(active && active.length > 0){
1812 var c = active.clone();
1822 if(active.length < 1){
1823 Roo.get(document).un("mouseup", onMouseDown);
1831 var last = active.last();
1832 lastShow = new Date();
1835 Roo.get(document).on("mouseup", onMouseDown);
1840 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1841 m.parentMenu.activeChild = m;
1842 }else if(last && last.isVisible()){
1843 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1848 function onBeforeHide(m){
1850 m.activeChild.hide();
1852 if(m.autoHideTimer){
1853 clearTimeout(m.autoHideTimer);
1854 delete m.autoHideTimer;
1859 function onBeforeShow(m){
1860 var pm = m.parentMenu;
1861 if(!pm && !m.allowOtherMenus){
1863 }else if(pm && pm.activeChild && active != m){
1864 pm.activeChild.hide();
1868 // private this should really trigger on mouseup..
1869 function onMouseDown(e){
1870 Roo.log("on Mouse Up");
1872 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1873 Roo.log("MenuManager hideAll");
1882 function onBeforeCheck(mi, state){
1884 var g = groups[mi.group];
1885 for(var i = 0, l = g.length; i < l; i++){
1887 g[i].setChecked(false);
1896 * Hides all menus that are currently visible
1898 hideAll : function(){
1903 register : function(menu){
1907 menus[menu.id] = menu;
1908 menu.on("beforehide", onBeforeHide);
1909 menu.on("hide", onHide);
1910 menu.on("beforeshow", onBeforeShow);
1911 menu.on("show", onShow);
1913 if(g && menu.events["checkchange"]){
1917 groups[g].push(menu);
1918 menu.on("checkchange", onCheck);
1923 * Returns a {@link Roo.menu.Menu} object
1924 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1925 * be used to generate and return a new Menu instance.
1927 get : function(menu){
1928 if(typeof menu == "string"){ // menu id
1930 }else if(menu.events){ // menu instance
1933 /*else if(typeof menu.length == 'number'){ // array of menu items?
1934 return new Roo.bootstrap.Menu({items:menu});
1935 }else{ // otherwise, must be a config
1936 return new Roo.bootstrap.Menu(menu);
1943 unregister : function(menu){
1944 delete menus[menu.id];
1945 menu.un("beforehide", onBeforeHide);
1946 menu.un("hide", onHide);
1947 menu.un("beforeshow", onBeforeShow);
1948 menu.un("show", onShow);
1950 if(g && menu.events["checkchange"]){
1951 groups[g].remove(menu);
1952 menu.un("checkchange", onCheck);
1957 registerCheckable : function(menuItem){
1958 var g = menuItem.group;
1963 groups[g].push(menuItem);
1964 menuItem.on("beforecheckchange", onBeforeCheck);
1969 unregisterCheckable : function(menuItem){
1970 var g = menuItem.group;
1972 groups[g].remove(menuItem);
1973 menuItem.un("beforecheckchange", onBeforeCheck);
1985 * @class Roo.bootstrap.Menu
1986 * @extends Roo.bootstrap.Component
1987 * Bootstrap Menu class - container for MenuItems
1988 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1989 * @cfg {bool} hidden if the menu should be hidden when rendered.
1990 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1991 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1995 * @param {Object} config The config object
1999 Roo.bootstrap.Menu = function(config){
2000 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2001 if (this.registerMenu && this.type != 'treeview') {
2002 Roo.bootstrap.MenuMgr.register(this);
2007 * Fires before this menu is displayed
2008 * @param {Roo.menu.Menu} this
2013 * Fires before this menu is hidden
2014 * @param {Roo.menu.Menu} this
2019 * Fires after this menu is displayed
2020 * @param {Roo.menu.Menu} this
2025 * Fires after this menu is hidden
2026 * @param {Roo.menu.Menu} this
2031 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2032 * @param {Roo.menu.Menu} this
2033 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2034 * @param {Roo.EventObject} e
2039 * Fires when the mouse is hovering over this menu
2040 * @param {Roo.menu.Menu} this
2041 * @param {Roo.EventObject} e
2042 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2047 * Fires when the mouse exits this menu
2048 * @param {Roo.menu.Menu} this
2049 * @param {Roo.EventObject} e
2050 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2055 * Fires when a menu item contained in this menu is clicked
2056 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2057 * @param {Roo.EventObject} e
2061 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2064 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2068 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2071 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2073 registerMenu : true,
2075 menuItems :false, // stores the menu items..
2085 getChildContainer : function() {
2089 getAutoCreate : function(){
2091 //if (['right'].indexOf(this.align)!==-1) {
2092 // cfg.cn[1].cls += ' pull-right'
2098 cls : 'dropdown-menu' ,
2099 style : 'z-index:1000'
2103 if (this.type === 'submenu') {
2104 cfg.cls = 'submenu active';
2106 if (this.type === 'treeview') {
2107 cfg.cls = 'treeview-menu';
2112 initEvents : function() {
2114 // Roo.log("ADD event");
2115 // Roo.log(this.triggerEl.dom);
2117 this.triggerEl.on('click', this.onTriggerClick, this);
2119 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2121 this.triggerEl.addClass('dropdown-toggle');
2124 this.el.on('touchstart' , this.onTouch, this);
2126 this.el.on('click' , this.onClick, this);
2128 this.el.on("mouseover", this.onMouseOver, this);
2129 this.el.on("mouseout", this.onMouseOut, this);
2133 findTargetItem : function(e)
2135 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2139 //Roo.log(t); Roo.log(t.id);
2141 //Roo.log(this.menuitems);
2142 return this.menuitems.get(t.id);
2144 //return this.items.get(t.menuItemId);
2150 onTouch : function(e)
2152 Roo.log("menu.onTouch");
2153 //e.stopEvent(); this make the user popdown broken
2157 onClick : function(e)
2159 Roo.log("menu.onClick");
2161 var t = this.findTargetItem(e);
2162 if(!t || t.isContainer){
2167 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2168 if(t == this.activeItem && t.shouldDeactivate(e)){
2169 this.activeItem.deactivate();
2170 delete this.activeItem;
2174 this.setActiveItem(t, true);
2182 Roo.log('pass click event');
2186 this.fireEvent("click", this, t, e);
2190 if(!t.href.length || t.href == '#'){
2191 (function() { _this.hide(); }).defer(100);
2196 onMouseOver : function(e){
2197 var t = this.findTargetItem(e);
2200 // if(t.canActivate && !t.disabled){
2201 // this.setActiveItem(t, true);
2205 this.fireEvent("mouseover", this, e, t);
2207 isVisible : function(){
2208 return !this.hidden;
2210 onMouseOut : function(e){
2211 var t = this.findTargetItem(e);
2214 // if(t == this.activeItem && t.shouldDeactivate(e)){
2215 // this.activeItem.deactivate();
2216 // delete this.activeItem;
2219 this.fireEvent("mouseout", this, e, t);
2224 * Displays this menu relative to another element
2225 * @param {String/HTMLElement/Roo.Element} element The element to align to
2226 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2227 * the element (defaults to this.defaultAlign)
2228 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2230 show : function(el, pos, parentMenu){
2231 this.parentMenu = parentMenu;
2235 this.fireEvent("beforeshow", this);
2236 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2239 * Displays this menu at a specific xy position
2240 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2241 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2243 showAt : function(xy, parentMenu, /* private: */_e){
2244 this.parentMenu = parentMenu;
2249 this.fireEvent("beforeshow", this);
2250 //xy = this.el.adjustForConstraints(xy);
2254 this.hideMenuItems();
2255 this.hidden = false;
2256 this.triggerEl.addClass('open');
2258 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2259 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2262 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2267 this.fireEvent("show", this);
2273 this.doFocus.defer(50, this);
2277 doFocus : function(){
2279 this.focusEl.focus();
2284 * Hides this menu and optionally all parent menus
2285 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2287 hide : function(deep)
2290 this.hideMenuItems();
2291 if(this.el && this.isVisible()){
2292 this.fireEvent("beforehide", this);
2293 if(this.activeItem){
2294 this.activeItem.deactivate();
2295 this.activeItem = null;
2297 this.triggerEl.removeClass('open');;
2299 this.fireEvent("hide", this);
2301 if(deep === true && this.parentMenu){
2302 this.parentMenu.hide(true);
2306 onTriggerClick : function(e)
2308 Roo.log('trigger click');
2310 var target = e.getTarget();
2312 Roo.log(target.nodeName.toLowerCase());
2314 if(target.nodeName.toLowerCase() === 'i'){
2320 onTriggerPress : function(e)
2322 Roo.log('trigger press');
2323 //Roo.log(e.getTarget());
2324 // Roo.log(this.triggerEl.dom);
2326 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2327 var pel = Roo.get(e.getTarget());
2328 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2329 Roo.log('is treeview or dropdown?');
2333 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2337 if (this.isVisible()) {
2342 this.show(this.triggerEl, false, false);
2345 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2352 hideMenuItems : function()
2354 Roo.log("hide Menu Items");
2358 //$(backdrop).remove()
2359 this.el.select('.open',true).each(function(aa) {
2361 aa.removeClass('open');
2362 //var parent = getParent($(this))
2363 //var relatedTarget = { relatedTarget: this }
2365 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2366 //if (e.isDefaultPrevented()) return
2367 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2370 addxtypeChild : function (tree, cntr) {
2371 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2373 this.menuitems.add(comp);
2385 this.getEl().dom.innerHTML = '';
2386 this.menuitems.clear();
2400 * @class Roo.bootstrap.MenuItem
2401 * @extends Roo.bootstrap.Component
2402 * Bootstrap MenuItem class
2403 * @cfg {String} html the menu label
2404 * @cfg {String} href the link
2405 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2406 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2407 * @cfg {Boolean} active used on sidebars to highlight active itesm
2408 * @cfg {String} fa favicon to show on left of menu item.
2409 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2413 * Create a new MenuItem
2414 * @param {Object} config The config object
2418 Roo.bootstrap.MenuItem = function(config){
2419 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2424 * The raw click event for the entire grid.
2425 * @param {Roo.bootstrap.MenuItem} this
2426 * @param {Roo.EventObject} e
2432 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2436 preventDefault: false,
2437 isContainer : false,
2441 getAutoCreate : function(){
2443 if(this.isContainer){
2446 cls: 'dropdown-menu-item'
2460 if (this.fa !== false) {
2463 cls : 'fa fa-' + this.fa
2472 cls: 'dropdown-menu-item',
2475 if (this.parent().type == 'treeview') {
2476 cfg.cls = 'treeview-menu';
2479 cfg.cls += ' active';
2484 anc.href = this.href || cfg.cn[0].href ;
2485 ctag.html = this.html || cfg.cn[0].html ;
2489 initEvents: function()
2491 if (this.parent().type == 'treeview') {
2492 this.el.select('a').on('click', this.onClick, this);
2496 this.menu.parentType = this.xtype;
2497 this.menu.triggerEl = this.el;
2498 this.menu = this.addxtype(Roo.apply({}, this.menu));
2502 onClick : function(e)
2504 Roo.log('item on click ');
2506 if(this.preventDefault){
2509 //this.parent().hideMenuItems();
2511 this.fireEvent('click', this, e);
2530 * @class Roo.bootstrap.MenuSeparator
2531 * @extends Roo.bootstrap.Component
2532 * Bootstrap MenuSeparator class
2535 * Create a new MenuItem
2536 * @param {Object} config The config object
2540 Roo.bootstrap.MenuSeparator = function(config){
2541 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2544 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2546 getAutoCreate : function(){
2565 * @class Roo.bootstrap.Modal
2566 * @extends Roo.bootstrap.Component
2567 * Bootstrap Modal class
2568 * @cfg {String} title Title of dialog
2569 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2570 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2571 * @cfg {Boolean} specificTitle default false
2572 * @cfg {Array} buttons Array of buttons or standard button set..
2573 * @cfg {String} buttonPosition (left|right|center) default right
2574 * @cfg {Boolean} animate default true
2575 * @cfg {Boolean} allow_close default true
2576 * @cfg {Boolean} fitwindow default false
2577 * @cfg {String} size (sm|lg) default empty
2581 * Create a new Modal Dialog
2582 * @param {Object} config The config object
2585 Roo.bootstrap.Modal = function(config){
2586 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2591 * The raw btnclick event for the button
2592 * @param {Roo.EventObject} e
2597 * Fire when dialog resize
2598 * @param {Roo.bootstrap.Modal} this
2599 * @param {Roo.EventObject} e
2603 this.buttons = this.buttons || [];
2606 this.tmpl = Roo.factory(this.tmpl);
2611 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2613 title : 'test dialog',
2623 specificTitle: false,
2625 buttonPosition: 'right',
2644 onRender : function(ct, position)
2646 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2649 var cfg = Roo.apply({}, this.getAutoCreate());
2652 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2654 //if (!cfg.name.length) {
2658 cfg.cls += ' ' + this.cls;
2661 cfg.style = this.style;
2663 this.el = Roo.get(document.body).createChild(cfg, position);
2665 //var type = this.el.dom.type;
2668 if(this.tabIndex !== undefined){
2669 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2672 this.dialogEl = this.el.select('.modal-dialog',true).first();
2673 this.bodyEl = this.el.select('.modal-body',true).first();
2674 this.closeEl = this.el.select('.modal-header .close', true).first();
2675 this.headerEl = this.el.select('.modal-header',true).first();
2676 this.titleEl = this.el.select('.modal-title',true).first();
2677 this.footerEl = this.el.select('.modal-footer',true).first();
2679 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2680 this.maskEl.enableDisplayMode("block");
2682 //this.el.addClass("x-dlg-modal");
2684 if (this.buttons.length) {
2685 Roo.each(this.buttons, function(bb) {
2686 var b = Roo.apply({}, bb);
2687 b.xns = b.xns || Roo.bootstrap;
2688 b.xtype = b.xtype || 'Button';
2689 if (typeof(b.listeners) == 'undefined') {
2690 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2693 var btn = Roo.factory(b);
2695 btn.render(this.el.select('.modal-footer div').first());
2699 // render the children.
2702 if(typeof(this.items) != 'undefined'){
2703 var items = this.items;
2706 for(var i =0;i < items.length;i++) {
2707 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2711 this.items = nitems;
2713 // where are these used - they used to be body/close/footer
2717 //this.el.addClass([this.fieldClass, this.cls]);
2721 getAutoCreate : function(){
2726 html : this.html || ''
2731 cls : 'modal-title',
2735 if(this.specificTitle){
2741 if (this.allow_close) {
2753 if(this.size.length){
2754 size = 'modal-' + this.size;
2759 style : 'display: none',
2762 cls: "modal-dialog " + size,
2765 cls : "modal-content",
2768 cls : 'modal-header',
2773 cls : 'modal-footer',
2777 cls: 'btn-' + this.buttonPosition
2794 modal.cls += ' fade';
2800 getChildContainer : function() {
2805 getButtonContainer : function() {
2806 return this.el.select('.modal-footer div',true).first();
2809 initEvents : function()
2811 if (this.allow_close) {
2812 this.closeEl.on('click', this.hide, this);
2814 Roo.EventManager.onWindowResize(this.resize, this, true);
2821 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2822 if (this.fitwindow) {
2823 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2824 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2829 setSize : function(w,h)
2839 if (!this.rendered) {
2843 this.el.setStyle('display', 'block');
2845 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2848 this.el.addClass('in');
2851 this.el.addClass('in');
2855 // not sure how we can show data in here..
2857 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2860 Roo.get(document.body).addClass("x-body-masked");
2862 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2863 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2868 this.fireEvent('show', this);
2870 // set zindex here - otherwise it appears to be ignored...
2871 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2874 this.items.forEach( function(e) {
2875 e.layout ? e.layout() : false;
2883 if(this.fireEvent("beforehide", this) !== false){
2885 Roo.get(document.body).removeClass("x-body-masked");
2886 this.el.removeClass('in');
2887 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2889 if(this.animate){ // why
2891 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2893 this.el.setStyle('display', 'none');
2895 this.fireEvent('hide', this);
2899 addButton : function(str, cb)
2903 var b = Roo.apply({}, { html : str } );
2904 b.xns = b.xns || Roo.bootstrap;
2905 b.xtype = b.xtype || 'Button';
2906 if (typeof(b.listeners) == 'undefined') {
2907 b.listeners = { click : cb.createDelegate(this) };
2910 var btn = Roo.factory(b);
2912 btn.render(this.el.select('.modal-footer div').first());
2918 setDefaultButton : function(btn)
2920 //this.el.select('.modal-footer').()
2924 resizeTo: function(w,h)
2928 this.dialogEl.setWidth(w);
2929 if (this.diff === false) {
2930 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2933 this.bodyEl.setHeight(h-this.diff);
2935 this.fireEvent('resize', this);
2938 setContentSize : function(w, h)
2942 onButtonClick: function(btn,e)
2945 this.fireEvent('btnclick', btn.name, e);
2948 * Set the title of the Dialog
2949 * @param {String} str new Title
2951 setTitle: function(str) {
2952 this.titleEl.dom.innerHTML = str;
2955 * Set the body of the Dialog
2956 * @param {String} str new Title
2958 setBody: function(str) {
2959 this.bodyEl.dom.innerHTML = str;
2962 * Set the body of the Dialog using the template
2963 * @param {Obj} data - apply this data to the template and replace the body contents.
2965 applyBody: function(obj)
2968 Roo.log("Error - using apply Body without a template");
2971 this.tmpl.overwrite(this.bodyEl, obj);
2977 Roo.apply(Roo.bootstrap.Modal, {
2979 * Button config that displays a single OK button
2988 * Button config that displays Yes and No buttons
3004 * Button config that displays OK and Cancel buttons
3019 * Button config that displays Yes, No and Cancel buttons
3043 * messagebox - can be used as a replace
3047 * @class Roo.MessageBox
3048 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3052 Roo.Msg.alert('Status', 'Changes saved successfully.');
3054 // Prompt for user data:
3055 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3057 // process text value...
3061 // Show a dialog using config options:
3063 title:'Save Changes?',
3064 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3065 buttons: Roo.Msg.YESNOCANCEL,
3072 Roo.bootstrap.MessageBox = function(){
3073 var dlg, opt, mask, waitTimer;
3074 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3075 var buttons, activeTextEl, bwidth;
3079 var handleButton = function(button){
3081 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3085 var handleHide = function(){
3087 dlg.el.removeClass(opt.cls);
3090 // Roo.TaskMgr.stop(waitTimer);
3091 // waitTimer = null;
3096 var updateButtons = function(b){
3099 buttons["ok"].hide();
3100 buttons["cancel"].hide();
3101 buttons["yes"].hide();
3102 buttons["no"].hide();
3103 //dlg.footer.dom.style.display = 'none';
3106 dlg.footerEl.dom.style.display = '';
3107 for(var k in buttons){
3108 if(typeof buttons[k] != "function"){
3111 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3112 width += buttons[k].el.getWidth()+15;
3122 var handleEsc = function(d, k, e){
3123 if(opt && opt.closable !== false){
3133 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3134 * @return {Roo.BasicDialog} The BasicDialog element
3136 getDialog : function(){
3138 dlg = new Roo.bootstrap.Modal( {
3141 //constraintoviewport:false,
3143 //collapsible : false,
3148 //buttonAlign:"center",
3149 closeClick : function(){
3150 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3153 handleButton("cancel");
3158 dlg.on("hide", handleHide);
3160 //dlg.addKeyListener(27, handleEsc);
3162 this.buttons = buttons;
3163 var bt = this.buttonText;
3164 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3165 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3166 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3167 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3169 bodyEl = dlg.bodyEl.createChild({
3171 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3172 '<textarea class="roo-mb-textarea"></textarea>' +
3173 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3175 msgEl = bodyEl.dom.firstChild;
3176 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3177 textboxEl.enableDisplayMode();
3178 textboxEl.addKeyListener([10,13], function(){
3179 if(dlg.isVisible() && opt && opt.buttons){
3182 }else if(opt.buttons.yes){
3183 handleButton("yes");
3187 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3188 textareaEl.enableDisplayMode();
3189 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3190 progressEl.enableDisplayMode();
3192 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3193 var pf = progressEl.dom.firstChild;
3195 pp = Roo.get(pf.firstChild);
3196 pp.setHeight(pf.offsetHeight);
3204 * Updates the message box body text
3205 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3206 * the XHTML-compliant non-breaking space character '&#160;')
3207 * @return {Roo.MessageBox} This message box
3209 updateText : function(text)
3211 if(!dlg.isVisible() && !opt.width){
3212 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3213 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3215 msgEl.innerHTML = text || ' ';
3217 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3218 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3220 Math.min(opt.width || cw , this.maxWidth),
3221 Math.max(opt.minWidth || this.minWidth, bwidth)
3224 activeTextEl.setWidth(w);
3226 if(dlg.isVisible()){
3227 dlg.fixedcenter = false;
3229 // to big, make it scroll. = But as usual stupid IE does not support
3232 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3233 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3234 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3236 bodyEl.dom.style.height = '';
3237 bodyEl.dom.style.overflowY = '';
3240 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3242 bodyEl.dom.style.overflowX = '';
3245 dlg.setContentSize(w, bodyEl.getHeight());
3246 if(dlg.isVisible()){
3247 dlg.fixedcenter = true;
3253 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3254 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3255 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3256 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3257 * @return {Roo.MessageBox} This message box
3259 updateProgress : function(value, text){
3261 this.updateText(text);
3264 if (pp) { // weird bug on my firefox - for some reason this is not defined
3265 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3266 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3272 * Returns true if the message box is currently displayed
3273 * @return {Boolean} True if the message box is visible, else false
3275 isVisible : function(){
3276 return dlg && dlg.isVisible();
3280 * Hides the message box if it is displayed
3283 if(this.isVisible()){
3289 * Displays a new message box, or reinitializes an existing message box, based on the config options
3290 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3291 * The following config object properties are supported:
3293 Property Type Description
3294 ---------- --------------- ------------------------------------------------------------------------------------
3295 animEl String/Element An id or Element from which the message box should animate as it opens and
3296 closes (defaults to undefined)
3297 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3298 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3299 closable Boolean False to hide the top-right close button (defaults to true). Note that
3300 progress and wait dialogs will ignore this property and always hide the
3301 close button as they can only be closed programmatically.
3302 cls String A custom CSS class to apply to the message box element
3303 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3304 displayed (defaults to 75)
3305 fn Function A callback function to execute after closing the dialog. The arguments to the
3306 function will be btn (the name of the button that was clicked, if applicable,
3307 e.g. "ok"), and text (the value of the active text field, if applicable).
3308 Progress and wait dialogs will ignore this option since they do not respond to
3309 user actions and can only be closed programmatically, so any required function
3310 should be called by the same code after it closes the dialog.
3311 icon String A CSS class that provides a background image to be used as an icon for
3312 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3313 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3314 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3315 modal Boolean False to allow user interaction with the page while the message box is
3316 displayed (defaults to true)
3317 msg String A string that will replace the existing message box body text (defaults
3318 to the XHTML-compliant non-breaking space character ' ')
3319 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3320 progress Boolean True to display a progress bar (defaults to false)
3321 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3322 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3323 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3324 title String The title text
3325 value String The string value to set into the active textbox element if displayed
3326 wait Boolean True to display a progress bar (defaults to false)
3327 width Number The width of the dialog in pixels
3334 msg: 'Please enter your address:',
3336 buttons: Roo.MessageBox.OKCANCEL,
3339 animEl: 'addAddressBtn'
3342 * @param {Object} config Configuration options
3343 * @return {Roo.MessageBox} This message box
3345 show : function(options)
3348 // this causes nightmares if you show one dialog after another
3349 // especially on callbacks..
3351 if(this.isVisible()){
3354 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3355 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3356 Roo.log("New Dialog Message:" + options.msg )
3357 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3358 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3361 var d = this.getDialog();
3363 d.setTitle(opt.title || " ");
3364 d.closeEl.setDisplayed(opt.closable !== false);
3365 activeTextEl = textboxEl;
3366 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3371 textareaEl.setHeight(typeof opt.multiline == "number" ?
3372 opt.multiline : this.defaultTextHeight);
3373 activeTextEl = textareaEl;
3382 progressEl.setDisplayed(opt.progress === true);
3383 this.updateProgress(0);
3384 activeTextEl.dom.value = opt.value || "";
3386 dlg.setDefaultButton(activeTextEl);
3388 var bs = opt.buttons;
3392 }else if(bs && bs.yes){
3393 db = buttons["yes"];
3395 dlg.setDefaultButton(db);
3397 bwidth = updateButtons(opt.buttons);
3398 this.updateText(opt.msg);
3400 d.el.addClass(opt.cls);
3402 d.proxyDrag = opt.proxyDrag === true;
3403 d.modal = opt.modal !== false;
3404 d.mask = opt.modal !== false ? mask : false;
3406 // force it to the end of the z-index stack so it gets a cursor in FF
3407 document.body.appendChild(dlg.el.dom);
3408 d.animateTarget = null;
3409 d.show(options.animEl);
3415 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3416 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3417 * and closing the message box when the process is complete.
3418 * @param {String} title The title bar text
3419 * @param {String} msg The message box body text
3420 * @return {Roo.MessageBox} This message box
3422 progress : function(title, msg){
3429 minWidth: this.minProgressWidth,
3436 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3437 * If a callback function is passed it will be called after the user clicks the button, and the
3438 * id of the button that was clicked will be passed as the only parameter to the callback
3439 * (could also be the top-right close button).
3440 * @param {String} title The title bar text
3441 * @param {String} msg The message box body text
3442 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3443 * @param {Object} scope (optional) The scope of the callback function
3444 * @return {Roo.MessageBox} This message box
3446 alert : function(title, msg, fn, scope)
3461 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3462 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3463 * You are responsible for closing the message box when the process is complete.
3464 * @param {String} msg The message box body text
3465 * @param {String} title (optional) The title bar text
3466 * @return {Roo.MessageBox} This message box
3468 wait : function(msg, title){
3479 waitTimer = Roo.TaskMgr.start({
3481 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3489 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3490 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3491 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3492 * @param {String} title The title bar text
3493 * @param {String} msg The message box body text
3494 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3495 * @param {Object} scope (optional) The scope of the callback function
3496 * @return {Roo.MessageBox} This message box
3498 confirm : function(title, msg, fn, scope){
3502 buttons: this.YESNO,
3511 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3512 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3513 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3514 * (could also be the top-right close button) and the text that was entered will be passed as the two
3515 * parameters to the callback.
3516 * @param {String} title The title bar text
3517 * @param {String} msg The message box body text
3518 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3519 * @param {Object} scope (optional) The scope of the callback function
3520 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3521 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3522 * @return {Roo.MessageBox} This message box
3524 prompt : function(title, msg, fn, scope, multiline){
3528 buttons: this.OKCANCEL,
3533 multiline: multiline,
3540 * Button config that displays a single OK button
3545 * Button config that displays Yes and No buttons
3548 YESNO : {yes:true, no:true},
3550 * Button config that displays OK and Cancel buttons
3553 OKCANCEL : {ok:true, cancel:true},
3555 * Button config that displays Yes, No and Cancel buttons
3558 YESNOCANCEL : {yes:true, no:true, cancel:true},
3561 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3564 defaultTextHeight : 75,
3566 * The maximum width in pixels of the message box (defaults to 600)
3571 * The minimum width in pixels of the message box (defaults to 100)
3576 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3577 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3580 minProgressWidth : 250,
3582 * An object containing the default button text strings that can be overriden for localized language support.
3583 * Supported properties are: ok, cancel, yes and no.
3584 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3597 * Shorthand for {@link Roo.MessageBox}
3599 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3600 Roo.Msg = Roo.Msg || Roo.MessageBox;
3609 * @class Roo.bootstrap.Navbar
3610 * @extends Roo.bootstrap.Component
3611 * Bootstrap Navbar class
3614 * Create a new Navbar
3615 * @param {Object} config The config object
3619 Roo.bootstrap.Navbar = function(config){
3620 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3624 * @event beforetoggle
3625 * Fire before toggle the menu
3626 * @param {Roo.EventObject} e
3628 "beforetoggle" : true
3632 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3641 getAutoCreate : function(){
3644 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3648 initEvents :function ()
3650 //Roo.log(this.el.select('.navbar-toggle',true));
3651 this.el.select('.navbar-toggle',true).on('click', function() {
3652 if(this.fireEvent('beforetoggle', this) !== false){
3653 this.el.select('.navbar-collapse',true).toggleClass('in');
3663 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3665 var size = this.el.getSize();
3666 this.maskEl.setSize(size.width, size.height);
3667 this.maskEl.enableDisplayMode("block");
3676 getChildContainer : function()
3678 if (this.el.select('.collapse').getCount()) {
3679 return this.el.select('.collapse',true).first();
3712 * @class Roo.bootstrap.NavSimplebar
3713 * @extends Roo.bootstrap.Navbar
3714 * Bootstrap Sidebar class
3716 * @cfg {Boolean} inverse is inverted color
3718 * @cfg {String} type (nav | pills | tabs)
3719 * @cfg {Boolean} arrangement stacked | justified
3720 * @cfg {String} align (left | right) alignment
3722 * @cfg {Boolean} main (true|false) main nav bar? default false
3723 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3725 * @cfg {String} tag (header|footer|nav|div) default is nav
3731 * Create a new Sidebar
3732 * @param {Object} config The config object
3736 Roo.bootstrap.NavSimplebar = function(config){
3737 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3740 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3756 getAutoCreate : function(){
3760 tag : this.tag || 'div',
3773 this.type = this.type || 'nav';
3774 if (['tabs','pills'].indexOf(this.type)!==-1) {
3775 cfg.cn[0].cls += ' nav-' + this.type
3779 if (this.type!=='nav') {
3780 Roo.log('nav type must be nav/tabs/pills')
3782 cfg.cn[0].cls += ' navbar-nav'
3788 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3789 cfg.cn[0].cls += ' nav-' + this.arrangement;
3793 if (this.align === 'right') {
3794 cfg.cn[0].cls += ' navbar-right';
3798 cfg.cls += ' navbar-inverse';
3825 * @class Roo.bootstrap.NavHeaderbar
3826 * @extends Roo.bootstrap.NavSimplebar
3827 * Bootstrap Sidebar class
3829 * @cfg {String} brand what is brand
3830 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3831 * @cfg {String} brand_href href of the brand
3832 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3833 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3834 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3835 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3838 * Create a new Sidebar
3839 * @param {Object} config The config object
3843 Roo.bootstrap.NavHeaderbar = function(config){
3844 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3848 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3855 desktopCenter : false,
3858 getAutoCreate : function(){
3861 tag: this.nav || 'nav',
3868 if (this.desktopCenter) {
3869 cn.push({cls : 'container', cn : []});
3876 cls: 'navbar-header',
3881 cls: 'navbar-toggle',
3882 'data-toggle': 'collapse',
3887 html: 'Toggle navigation'
3909 cls: 'collapse navbar-collapse',
3913 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3915 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3916 cfg.cls += ' navbar-' + this.position;
3918 // tag can override this..
3920 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3923 if (this.brand !== '') {
3926 href: this.brand_href ? this.brand_href : '#',
3927 cls: 'navbar-brand',
3935 cfg.cls += ' main-nav';
3943 getHeaderChildContainer : function()
3945 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3946 return this.el.select('.navbar-header',true).first();
3949 return this.getChildContainer();
3953 initEvents : function()
3955 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3957 if (this.autohide) {
3962 Roo.get(document).on('scroll',function(e) {
3963 var ns = Roo.get(document).getScroll().top;
3964 var os = prevScroll;
3968 ft.removeClass('slideDown');
3969 ft.addClass('slideUp');
3972 ft.removeClass('slideUp');
3973 ft.addClass('slideDown');
3994 * @class Roo.bootstrap.NavSidebar
3995 * @extends Roo.bootstrap.Navbar
3996 * Bootstrap Sidebar class
3999 * Create a new Sidebar
4000 * @param {Object} config The config object
4004 Roo.bootstrap.NavSidebar = function(config){
4005 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4008 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4010 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4012 getAutoCreate : function(){
4017 cls: 'sidebar sidebar-nav'
4039 * @class Roo.bootstrap.NavGroup
4040 * @extends Roo.bootstrap.Component
4041 * Bootstrap NavGroup class
4042 * @cfg {String} align (left|right)
4043 * @cfg {Boolean} inverse
4044 * @cfg {String} type (nav|pills|tab) default nav
4045 * @cfg {String} navId - reference Id for navbar.
4049 * Create a new nav group
4050 * @param {Object} config The config object
4053 Roo.bootstrap.NavGroup = function(config){
4054 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4057 Roo.bootstrap.NavGroup.register(this);
4061 * Fires when the active item changes
4062 * @param {Roo.bootstrap.NavGroup} this
4063 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4064 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4071 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4082 getAutoCreate : function()
4084 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4091 if (['tabs','pills'].indexOf(this.type)!==-1) {
4092 cfg.cls += ' nav-' + this.type
4094 if (this.type!=='nav') {
4095 Roo.log('nav type must be nav/tabs/pills')
4097 cfg.cls += ' navbar-nav'
4100 if (this.parent() && this.parent().sidebar) {
4103 cls: 'dashboard-menu sidebar-menu'
4109 if (this.form === true) {
4115 if (this.align === 'right') {
4116 cfg.cls += ' navbar-right';
4118 cfg.cls += ' navbar-left';
4122 if (this.align === 'right') {
4123 cfg.cls += ' navbar-right';
4127 cfg.cls += ' navbar-inverse';
4135 * sets the active Navigation item
4136 * @param {Roo.bootstrap.NavItem} the new current navitem
4138 setActiveItem : function(item)
4141 Roo.each(this.navItems, function(v){
4146 v.setActive(false, true);
4153 item.setActive(true, true);
4154 this.fireEvent('changed', this, item, prev);
4159 * gets the active Navigation item
4160 * @return {Roo.bootstrap.NavItem} the current navitem
4162 getActive : function()
4166 Roo.each(this.navItems, function(v){
4177 indexOfNav : function()
4181 Roo.each(this.navItems, function(v,i){
4192 * adds a Navigation item
4193 * @param {Roo.bootstrap.NavItem} the navitem to add
4195 addItem : function(cfg)
4197 var cn = new Roo.bootstrap.NavItem(cfg);
4199 cn.parentId = this.id;
4200 cn.onRender(this.el, null);
4204 * register a Navigation item
4205 * @param {Roo.bootstrap.NavItem} the navitem to add
4207 register : function(item)
4209 this.navItems.push( item);
4210 item.navId = this.navId;
4215 * clear all the Navigation item
4218 clearAll : function()
4221 this.el.dom.innerHTML = '';
4224 getNavItem: function(tabId)
4227 Roo.each(this.navItems, function(e) {
4228 if (e.tabId == tabId) {
4238 setActiveNext : function()
4240 var i = this.indexOfNav(this.getActive());
4241 if (i > this.navItems.length) {
4244 this.setActiveItem(this.navItems[i+1]);
4246 setActivePrev : function()
4248 var i = this.indexOfNav(this.getActive());
4252 this.setActiveItem(this.navItems[i-1]);
4254 clearWasActive : function(except) {
4255 Roo.each(this.navItems, function(e) {
4256 if (e.tabId != except.tabId && e.was_active) {
4257 e.was_active = false;
4264 getWasActive : function ()
4267 Roo.each(this.navItems, function(e) {
4282 Roo.apply(Roo.bootstrap.NavGroup, {
4286 * register a Navigation Group
4287 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4289 register : function(navgrp)
4291 this.groups[navgrp.navId] = navgrp;
4295 * fetch a Navigation Group based on the navigation ID
4296 * @param {string} the navgroup to add
4297 * @returns {Roo.bootstrap.NavGroup} the navgroup
4299 get: function(navId) {
4300 if (typeof(this.groups[navId]) == 'undefined') {
4302 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4304 return this.groups[navId] ;
4319 * @class Roo.bootstrap.NavItem
4320 * @extends Roo.bootstrap.Component
4321 * Bootstrap Navbar.NavItem class
4322 * @cfg {String} href link to
4323 * @cfg {String} html content of button
4324 * @cfg {String} badge text inside badge
4325 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4326 * @cfg {String} glyphicon name of glyphicon
4327 * @cfg {String} icon name of font awesome icon
4328 * @cfg {Boolean} active Is item active
4329 * @cfg {Boolean} disabled Is item disabled
4331 * @cfg {Boolean} preventDefault (true | false) default false
4332 * @cfg {String} tabId the tab that this item activates.
4333 * @cfg {String} tagtype (a|span) render as a href or span?
4334 * @cfg {Boolean} animateRef (true|false) link to element default false
4337 * Create a new Navbar Item
4338 * @param {Object} config The config object
4340 Roo.bootstrap.NavItem = function(config){
4341 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4346 * The raw click event for the entire grid.
4347 * @param {Roo.EventObject} e
4352 * Fires when the active item active state changes
4353 * @param {Roo.bootstrap.NavItem} this
4354 * @param {boolean} state the new state
4360 * Fires when scroll to element
4361 * @param {Roo.bootstrap.NavItem} this
4362 * @param {Object} options
4363 * @param {Roo.EventObject} e
4371 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4379 preventDefault : false,
4386 getAutoCreate : function(){
4395 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4397 if (this.disabled) {
4398 cfg.cls += ' disabled';
4401 if (this.href || this.html || this.glyphicon || this.icon) {
4405 href : this.href || "#",
4406 html: this.html || ''
4411 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4414 if(this.glyphicon) {
4415 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4420 cfg.cn[0].html += " <span class='caret'></span>";
4424 if (this.badge !== '') {
4426 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4434 initEvents: function()
4436 if (typeof (this.menu) != 'undefined') {
4437 this.menu.parentType = this.xtype;
4438 this.menu.triggerEl = this.el;
4439 this.menu = this.addxtype(Roo.apply({}, this.menu));
4442 this.el.select('a',true).on('click', this.onClick, this);
4444 if(this.tagtype == 'span'){
4445 this.el.select('span',true).on('click', this.onClick, this);
4448 // at this point parent should be available..
4449 this.parent().register(this);
4452 onClick : function(e)
4454 if (e.getTarget('.dropdown-menu-item')) {
4455 // did you click on a menu itemm.... - then don't trigger onclick..
4460 this.preventDefault ||
4463 Roo.log("NavItem - prevent Default?");
4467 if (this.disabled) {
4471 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4472 if (tg && tg.transition) {
4473 Roo.log("waiting for the transitionend");
4479 //Roo.log("fire event clicked");
4480 if(this.fireEvent('click', this, e) === false){
4484 if(this.tagtype == 'span'){
4488 //Roo.log(this.href);
4489 var ael = this.el.select('a',true).first();
4492 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4493 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4494 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4495 return; // ignore... - it's a 'hash' to another page.
4497 Roo.log("NavItem - prevent Default?");
4499 this.scrollToElement(e);
4503 var p = this.parent();
4505 if (['tabs','pills'].indexOf(p.type)!==-1) {
4506 if (typeof(p.setActiveItem) !== 'undefined') {
4507 p.setActiveItem(this);
4511 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4512 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4513 // remove the collapsed menu expand...
4514 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4518 isActive: function () {
4521 setActive : function(state, fire, is_was_active)
4523 if (this.active && !state && this.navId) {
4524 this.was_active = true;
4525 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4527 nv.clearWasActive(this);
4531 this.active = state;
4534 this.el.removeClass('active');
4535 } else if (!this.el.hasClass('active')) {
4536 this.el.addClass('active');
4539 this.fireEvent('changed', this, state);
4542 // show a panel if it's registered and related..
4544 if (!this.navId || !this.tabId || !state || is_was_active) {
4548 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4552 var pan = tg.getPanelByName(this.tabId);
4556 // if we can not flip to new panel - go back to old nav highlight..
4557 if (false == tg.showPanel(pan)) {
4558 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4560 var onav = nv.getWasActive();
4562 onav.setActive(true, false, true);
4571 // this should not be here...
4572 setDisabled : function(state)
4574 this.disabled = state;
4576 this.el.removeClass('disabled');
4577 } else if (!this.el.hasClass('disabled')) {
4578 this.el.addClass('disabled');
4584 * Fetch the element to display the tooltip on.
4585 * @return {Roo.Element} defaults to this.el
4587 tooltipEl : function()
4589 return this.el.select('' + this.tagtype + '', true).first();
4592 scrollToElement : function(e)
4594 var c = document.body;
4597 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4599 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4600 c = document.documentElement;
4603 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4609 var o = target.calcOffsetsTo(c);
4616 this.fireEvent('scrollto', this, options, e);
4618 Roo.get(c).scrollTo('top', options.value, true);
4631 * <span> icon </span>
4632 * <span> text </span>
4633 * <span>badge </span>
4637 * @class Roo.bootstrap.NavSidebarItem
4638 * @extends Roo.bootstrap.NavItem
4639 * Bootstrap Navbar.NavSidebarItem class
4640 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4641 * {Boolean} open is the menu open
4642 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4643 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4644 * {String} buttonSize (sm|md|lg)the extra classes for the button
4645 * {Boolean} showArrow show arrow next to the text (default true)
4647 * Create a new Navbar Button
4648 * @param {Object} config The config object
4650 Roo.bootstrap.NavSidebarItem = function(config){
4651 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4656 * The raw click event for the entire grid.
4657 * @param {Roo.EventObject} e
4662 * Fires when the active item active state changes
4663 * @param {Roo.bootstrap.NavSidebarItem} this
4664 * @param {boolean} state the new state
4672 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4674 badgeWeight : 'default',
4680 buttonWeight : 'default',
4686 getAutoCreate : function(){
4691 href : this.href || '#',
4697 if(this.buttonView){
4700 href : this.href || '#',
4701 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4714 cfg.cls += ' active';
4717 if (this.disabled) {
4718 cfg.cls += ' disabled';
4721 cfg.cls += ' open x-open';
4724 if (this.glyphicon || this.icon) {
4725 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4726 a.cn.push({ tag : 'i', cls : c }) ;
4729 if(!this.buttonView){
4732 html : this.html || ''
4739 if (this.badge !== '') {
4740 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4746 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4749 a.cls += ' dropdown-toggle treeview' ;
4755 initEvents : function()
4757 if (typeof (this.menu) != 'undefined') {
4758 this.menu.parentType = this.xtype;
4759 this.menu.triggerEl = this.el;
4760 this.menu = this.addxtype(Roo.apply({}, this.menu));
4763 this.el.on('click', this.onClick, this);
4765 if(this.badge !== ''){
4766 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4771 onClick : function(e)
4778 if(this.preventDefault){
4782 this.fireEvent('click', this);
4785 disable : function()
4787 this.setDisabled(true);
4792 this.setDisabled(false);
4795 setDisabled : function(state)
4797 if(this.disabled == state){
4801 this.disabled = state;
4804 this.el.addClass('disabled');
4808 this.el.removeClass('disabled');
4813 setActive : function(state)
4815 if(this.active == state){
4819 this.active = state;
4822 this.el.addClass('active');
4826 this.el.removeClass('active');
4831 isActive: function ()
4836 setBadge : function(str)
4842 this.badgeEl.dom.innerHTML = str;
4859 * @class Roo.bootstrap.Row
4860 * @extends Roo.bootstrap.Component
4861 * Bootstrap Row class (contains columns...)
4865 * @param {Object} config The config object
4868 Roo.bootstrap.Row = function(config){
4869 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4872 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4874 getAutoCreate : function(){
4893 * @class Roo.bootstrap.Element
4894 * @extends Roo.bootstrap.Component
4895 * Bootstrap Element class
4896 * @cfg {String} html contents of the element
4897 * @cfg {String} tag tag of the element
4898 * @cfg {String} cls class of the element
4899 * @cfg {Boolean} preventDefault (true|false) default false
4900 * @cfg {Boolean} clickable (true|false) default false
4903 * Create a new Element
4904 * @param {Object} config The config object
4907 Roo.bootstrap.Element = function(config){
4908 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4914 * When a element is chick
4915 * @param {Roo.bootstrap.Element} this
4916 * @param {Roo.EventObject} e
4922 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4927 preventDefault: false,
4930 getAutoCreate : function(){
4941 initEvents: function()
4943 Roo.bootstrap.Element.superclass.initEvents.call(this);
4946 this.el.on('click', this.onClick, this);
4951 onClick : function(e)
4953 if(this.preventDefault){
4957 this.fireEvent('click', this, e);
4960 getValue : function()
4962 return this.el.dom.innerHTML;
4965 setValue : function(value)
4967 this.el.dom.innerHTML = value;
4982 * @class Roo.bootstrap.Pagination
4983 * @extends Roo.bootstrap.Component
4984 * Bootstrap Pagination class
4985 * @cfg {String} size xs | sm | md | lg
4986 * @cfg {Boolean} inverse false | true
4989 * Create a new Pagination
4990 * @param {Object} config The config object
4993 Roo.bootstrap.Pagination = function(config){
4994 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4997 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5003 getAutoCreate : function(){
5009 cfg.cls += ' inverse';
5015 cfg.cls += " " + this.cls;
5033 * @class Roo.bootstrap.PaginationItem
5034 * @extends Roo.bootstrap.Component
5035 * Bootstrap PaginationItem class
5036 * @cfg {String} html text
5037 * @cfg {String} href the link
5038 * @cfg {Boolean} preventDefault (true | false) default true
5039 * @cfg {Boolean} active (true | false) default false
5040 * @cfg {Boolean} disabled default false
5044 * Create a new PaginationItem
5045 * @param {Object} config The config object
5049 Roo.bootstrap.PaginationItem = function(config){
5050 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5055 * The raw click event for the entire grid.
5056 * @param {Roo.EventObject} e
5062 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5066 preventDefault: true,
5071 getAutoCreate : function(){
5077 href : this.href ? this.href : '#',
5078 html : this.html ? this.html : ''
5088 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5092 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5098 initEvents: function() {
5100 this.el.on('click', this.onClick, this);
5103 onClick : function(e)
5105 Roo.log('PaginationItem on click ');
5106 if(this.preventDefault){
5114 this.fireEvent('click', this, e);
5130 * @class Roo.bootstrap.Slider
5131 * @extends Roo.bootstrap.Component
5132 * Bootstrap Slider class
5135 * Create a new Slider
5136 * @param {Object} config The config object
5139 Roo.bootstrap.Slider = function(config){
5140 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5143 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5145 getAutoCreate : function(){
5149 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5153 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5165 * Ext JS Library 1.1.1
5166 * Copyright(c) 2006-2007, Ext JS, LLC.
5168 * Originally Released Under LGPL - original licence link has changed is not relivant.
5171 * <script type="text/javascript">
5176 * @class Roo.grid.ColumnModel
5177 * @extends Roo.util.Observable
5178 * This is the default implementation of a ColumnModel used by the Grid. It defines
5179 * the columns in the grid.
5182 var colModel = new Roo.grid.ColumnModel([
5183 {header: "Ticker", width: 60, sortable: true, locked: true},
5184 {header: "Company Name", width: 150, sortable: true},
5185 {header: "Market Cap.", width: 100, sortable: true},
5186 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5187 {header: "Employees", width: 100, sortable: true, resizable: false}
5192 * The config options listed for this class are options which may appear in each
5193 * individual column definition.
5194 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5196 * @param {Object} config An Array of column config objects. See this class's
5197 * config objects for details.
5199 Roo.grid.ColumnModel = function(config){
5201 * The config passed into the constructor
5203 this.config = config;
5206 // if no id, create one
5207 // if the column does not have a dataIndex mapping,
5208 // map it to the order it is in the config
5209 for(var i = 0, len = config.length; i < len; i++){
5211 if(typeof c.dataIndex == "undefined"){
5214 if(typeof c.renderer == "string"){
5215 c.renderer = Roo.util.Format[c.renderer];
5217 if(typeof c.id == "undefined"){
5220 if(c.editor && c.editor.xtype){
5221 c.editor = Roo.factory(c.editor, Roo.grid);
5223 if(c.editor && c.editor.isFormField){
5224 c.editor = new Roo.grid.GridEditor(c.editor);
5226 this.lookup[c.id] = c;
5230 * The width of columns which have no width specified (defaults to 100)
5233 this.defaultWidth = 100;
5236 * Default sortable of columns which have no sortable specified (defaults to false)
5239 this.defaultSortable = false;
5243 * @event widthchange
5244 * Fires when the width of a column changes.
5245 * @param {ColumnModel} this
5246 * @param {Number} columnIndex The column index
5247 * @param {Number} newWidth The new width
5249 "widthchange": true,
5251 * @event headerchange
5252 * Fires when the text of a header changes.
5253 * @param {ColumnModel} this
5254 * @param {Number} columnIndex The column index
5255 * @param {Number} newText The new header text
5257 "headerchange": true,
5259 * @event hiddenchange
5260 * Fires when a column is hidden or "unhidden".
5261 * @param {ColumnModel} this
5262 * @param {Number} columnIndex The column index
5263 * @param {Boolean} hidden true if hidden, false otherwise
5265 "hiddenchange": true,
5267 * @event columnmoved
5268 * Fires when a column is moved.
5269 * @param {ColumnModel} this
5270 * @param {Number} oldIndex
5271 * @param {Number} newIndex
5273 "columnmoved" : true,
5275 * @event columlockchange
5276 * Fires when a column's locked state is changed
5277 * @param {ColumnModel} this
5278 * @param {Number} colIndex
5279 * @param {Boolean} locked true if locked
5281 "columnlockchange" : true
5283 Roo.grid.ColumnModel.superclass.constructor.call(this);
5285 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5287 * @cfg {String} header The header text to display in the Grid view.
5290 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5291 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5292 * specified, the column's index is used as an index into the Record's data Array.
5295 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5296 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5299 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5300 * Defaults to the value of the {@link #defaultSortable} property.
5301 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5304 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5307 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5310 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5313 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5316 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5317 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5318 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5319 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5322 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5325 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5328 * @cfg {String} cursor (Optional)
5331 * @cfg {String} tooltip (Optional)
5334 * @cfg {Number} xs (Optional)
5337 * @cfg {Number} sm (Optional)
5340 * @cfg {Number} md (Optional)
5343 * @cfg {Number} lg (Optional)
5346 * Returns the id of the column at the specified index.
5347 * @param {Number} index The column index
5348 * @return {String} the id
5350 getColumnId : function(index){
5351 return this.config[index].id;
5355 * Returns the column for a specified id.
5356 * @param {String} id The column id
5357 * @return {Object} the column
5359 getColumnById : function(id){
5360 return this.lookup[id];
5365 * Returns the column for a specified dataIndex.
5366 * @param {String} dataIndex The column dataIndex
5367 * @return {Object|Boolean} the column or false if not found
5369 getColumnByDataIndex: function(dataIndex){
5370 var index = this.findColumnIndex(dataIndex);
5371 return index > -1 ? this.config[index] : false;
5375 * Returns the index for a specified column id.
5376 * @param {String} id The column id
5377 * @return {Number} the index, or -1 if not found
5379 getIndexById : function(id){
5380 for(var i = 0, len = this.config.length; i < len; i++){
5381 if(this.config[i].id == id){
5389 * Returns the index for a specified column dataIndex.
5390 * @param {String} dataIndex The column dataIndex
5391 * @return {Number} the index, or -1 if not found
5394 findColumnIndex : function(dataIndex){
5395 for(var i = 0, len = this.config.length; i < len; i++){
5396 if(this.config[i].dataIndex == dataIndex){
5404 moveColumn : function(oldIndex, newIndex){
5405 var c = this.config[oldIndex];
5406 this.config.splice(oldIndex, 1);
5407 this.config.splice(newIndex, 0, c);
5408 this.dataMap = null;
5409 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5412 isLocked : function(colIndex){
5413 return this.config[colIndex].locked === true;
5416 setLocked : function(colIndex, value, suppressEvent){
5417 if(this.isLocked(colIndex) == value){
5420 this.config[colIndex].locked = value;
5422 this.fireEvent("columnlockchange", this, colIndex, value);
5426 getTotalLockedWidth : function(){
5428 for(var i = 0; i < this.config.length; i++){
5429 if(this.isLocked(i) && !this.isHidden(i)){
5430 this.totalWidth += this.getColumnWidth(i);
5436 getLockedCount : function(){
5437 for(var i = 0, len = this.config.length; i < len; i++){
5438 if(!this.isLocked(i)){
5443 return this.config.length;
5447 * Returns the number of columns.
5450 getColumnCount : function(visibleOnly){
5451 if(visibleOnly === true){
5453 for(var i = 0, len = this.config.length; i < len; i++){
5454 if(!this.isHidden(i)){
5460 return this.config.length;
5464 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5465 * @param {Function} fn
5466 * @param {Object} scope (optional)
5467 * @return {Array} result
5469 getColumnsBy : function(fn, scope){
5471 for(var i = 0, len = this.config.length; i < len; i++){
5472 var c = this.config[i];
5473 if(fn.call(scope||this, c, i) === true){
5481 * Returns true if the specified column is sortable.
5482 * @param {Number} col The column index
5485 isSortable : function(col){
5486 if(typeof this.config[col].sortable == "undefined"){
5487 return this.defaultSortable;
5489 return this.config[col].sortable;
5493 * Returns the rendering (formatting) function defined for the column.
5494 * @param {Number} col The column index.
5495 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5497 getRenderer : function(col){
5498 if(!this.config[col].renderer){
5499 return Roo.grid.ColumnModel.defaultRenderer;
5501 return this.config[col].renderer;
5505 * Sets the rendering (formatting) function for a column.
5506 * @param {Number} col The column index
5507 * @param {Function} fn The function to use to process the cell's raw data
5508 * to return HTML markup for the grid view. The render function is called with
5509 * the following parameters:<ul>
5510 * <li>Data value.</li>
5511 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5512 * <li>css A CSS style string to apply to the table cell.</li>
5513 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5514 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5515 * <li>Row index</li>
5516 * <li>Column index</li>
5517 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5519 setRenderer : function(col, fn){
5520 this.config[col].renderer = fn;
5524 * Returns the width for the specified column.
5525 * @param {Number} col The column index
5528 getColumnWidth : function(col){
5529 return this.config[col].width * 1 || this.defaultWidth;
5533 * Sets the width for a column.
5534 * @param {Number} col The column index
5535 * @param {Number} width The new width
5537 setColumnWidth : function(col, width, suppressEvent){
5538 this.config[col].width = width;
5539 this.totalWidth = null;
5541 this.fireEvent("widthchange", this, col, width);
5546 * Returns the total width of all columns.
5547 * @param {Boolean} includeHidden True to include hidden column widths
5550 getTotalWidth : function(includeHidden){
5551 if(!this.totalWidth){
5552 this.totalWidth = 0;
5553 for(var i = 0, len = this.config.length; i < len; i++){
5554 if(includeHidden || !this.isHidden(i)){
5555 this.totalWidth += this.getColumnWidth(i);
5559 return this.totalWidth;
5563 * Returns the header for the specified column.
5564 * @param {Number} col The column index
5567 getColumnHeader : function(col){
5568 return this.config[col].header;
5572 * Sets the header for a column.
5573 * @param {Number} col The column index
5574 * @param {String} header The new header
5576 setColumnHeader : function(col, header){
5577 this.config[col].header = header;
5578 this.fireEvent("headerchange", this, col, header);
5582 * Returns the tooltip for the specified column.
5583 * @param {Number} col The column index
5586 getColumnTooltip : function(col){
5587 return this.config[col].tooltip;
5590 * Sets the tooltip for a column.
5591 * @param {Number} col The column index
5592 * @param {String} tooltip The new tooltip
5594 setColumnTooltip : function(col, tooltip){
5595 this.config[col].tooltip = tooltip;
5599 * Returns the dataIndex for the specified column.
5600 * @param {Number} col The column index
5603 getDataIndex : function(col){
5604 return this.config[col].dataIndex;
5608 * Sets the dataIndex for a column.
5609 * @param {Number} col The column index
5610 * @param {Number} dataIndex The new dataIndex
5612 setDataIndex : function(col, dataIndex){
5613 this.config[col].dataIndex = dataIndex;
5619 * Returns true if the cell is editable.
5620 * @param {Number} colIndex The column index
5621 * @param {Number} rowIndex The row index - this is nto actually used..?
5624 isCellEditable : function(colIndex, rowIndex){
5625 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5629 * Returns the editor defined for the cell/column.
5630 * return false or null to disable editing.
5631 * @param {Number} colIndex The column index
5632 * @param {Number} rowIndex The row index
5635 getCellEditor : function(colIndex, rowIndex){
5636 return this.config[colIndex].editor;
5640 * Sets if a column is editable.
5641 * @param {Number} col The column index
5642 * @param {Boolean} editable True if the column is editable
5644 setEditable : function(col, editable){
5645 this.config[col].editable = editable;
5650 * Returns true if the column is hidden.
5651 * @param {Number} colIndex The column index
5654 isHidden : function(colIndex){
5655 return this.config[colIndex].hidden;
5660 * Returns true if the column width cannot be changed
5662 isFixed : function(colIndex){
5663 return this.config[colIndex].fixed;
5667 * Returns true if the column can be resized
5670 isResizable : function(colIndex){
5671 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5674 * Sets if a column is hidden.
5675 * @param {Number} colIndex The column index
5676 * @param {Boolean} hidden True if the column is hidden
5678 setHidden : function(colIndex, hidden){
5679 this.config[colIndex].hidden = hidden;
5680 this.totalWidth = null;
5681 this.fireEvent("hiddenchange", this, colIndex, hidden);
5685 * Sets the editor for a column.
5686 * @param {Number} col The column index
5687 * @param {Object} editor The editor object
5689 setEditor : function(col, editor){
5690 this.config[col].editor = editor;
5694 Roo.grid.ColumnModel.defaultRenderer = function(value)
5696 if(typeof value == "object") {
5699 if(typeof value == "string" && value.length < 1){
5703 return String.format("{0}", value);
5706 // Alias for backwards compatibility
5707 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5710 * Ext JS Library 1.1.1
5711 * Copyright(c) 2006-2007, Ext JS, LLC.
5713 * Originally Released Under LGPL - original licence link has changed is not relivant.
5716 * <script type="text/javascript">
5720 * @class Roo.LoadMask
5721 * A simple utility class for generically masking elements while loading data. If the element being masked has
5722 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5723 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5724 * element's UpdateManager load indicator and will be destroyed after the initial load.
5726 * Create a new LoadMask
5727 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5728 * @param {Object} config The config object
5730 Roo.LoadMask = function(el, config){
5731 this.el = Roo.get(el);
5732 Roo.apply(this, config);
5734 this.store.on('beforeload', this.onBeforeLoad, this);
5735 this.store.on('load', this.onLoad, this);
5736 this.store.on('loadexception', this.onLoadException, this);
5737 this.removeMask = false;
5739 var um = this.el.getUpdateManager();
5740 um.showLoadIndicator = false; // disable the default indicator
5741 um.on('beforeupdate', this.onBeforeLoad, this);
5742 um.on('update', this.onLoad, this);
5743 um.on('failure', this.onLoad, this);
5744 this.removeMask = true;
5748 Roo.LoadMask.prototype = {
5750 * @cfg {Boolean} removeMask
5751 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5752 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5756 * The text to display in a centered loading message box (defaults to 'Loading...')
5760 * @cfg {String} msgCls
5761 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5763 msgCls : 'x-mask-loading',
5766 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5772 * Disables the mask to prevent it from being displayed
5774 disable : function(){
5775 this.disabled = true;
5779 * Enables the mask so that it can be displayed
5781 enable : function(){
5782 this.disabled = false;
5785 onLoadException : function()
5789 if (typeof(arguments[3]) != 'undefined') {
5790 Roo.MessageBox.alert("Error loading",arguments[3]);
5794 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5795 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5802 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5807 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5811 onBeforeLoad : function(){
5813 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5818 destroy : function(){
5820 this.store.un('beforeload', this.onBeforeLoad, this);
5821 this.store.un('load', this.onLoad, this);
5822 this.store.un('loadexception', this.onLoadException, this);
5824 var um = this.el.getUpdateManager();
5825 um.un('beforeupdate', this.onBeforeLoad, this);
5826 um.un('update', this.onLoad, this);
5827 um.un('failure', this.onLoad, this);
5838 * @class Roo.bootstrap.Table
5839 * @extends Roo.bootstrap.Component
5840 * Bootstrap Table class
5841 * @cfg {String} cls table class
5842 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5843 * @cfg {String} bgcolor Specifies the background color for a table
5844 * @cfg {Number} border Specifies whether the table cells should have borders or not
5845 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5846 * @cfg {Number} cellspacing Specifies the space between cells
5847 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5848 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5849 * @cfg {String} sortable Specifies that the table should be sortable
5850 * @cfg {String} summary Specifies a summary of the content of a table
5851 * @cfg {Number} width Specifies the width of a table
5852 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5854 * @cfg {boolean} striped Should the rows be alternative striped
5855 * @cfg {boolean} bordered Add borders to the table
5856 * @cfg {boolean} hover Add hover highlighting
5857 * @cfg {boolean} condensed Format condensed
5858 * @cfg {boolean} responsive Format condensed
5859 * @cfg {Boolean} loadMask (true|false) default false
5860 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5861 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5862 * @cfg {Boolean} rowSelection (true|false) default false
5863 * @cfg {Boolean} cellSelection (true|false) default false
5864 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5865 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5866 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5870 * Create a new Table
5871 * @param {Object} config The config object
5874 Roo.bootstrap.Table = function(config){
5875 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5880 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5881 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5882 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5883 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5885 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5887 this.sm.grid = this;
5888 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5889 this.sm = this.selModel;
5890 this.sm.xmodule = this.xmodule || false;
5893 if (this.cm && typeof(this.cm.config) == 'undefined') {
5894 this.colModel = new Roo.grid.ColumnModel(this.cm);
5895 this.cm = this.colModel;
5896 this.cm.xmodule = this.xmodule || false;
5899 this.store= Roo.factory(this.store, Roo.data);
5900 this.ds = this.store;
5901 this.ds.xmodule = this.xmodule || false;
5904 if (this.footer && this.store) {
5905 this.footer.dataSource = this.ds;
5906 this.footer = Roo.factory(this.footer);
5913 * Fires when a cell is clicked
5914 * @param {Roo.bootstrap.Table} this
5915 * @param {Roo.Element} el
5916 * @param {Number} rowIndex
5917 * @param {Number} columnIndex
5918 * @param {Roo.EventObject} e
5922 * @event celldblclick
5923 * Fires when a cell is double clicked
5924 * @param {Roo.bootstrap.Table} this
5925 * @param {Roo.Element} el
5926 * @param {Number} rowIndex
5927 * @param {Number} columnIndex
5928 * @param {Roo.EventObject} e
5930 "celldblclick" : true,
5933 * Fires when a row is clicked
5934 * @param {Roo.bootstrap.Table} this
5935 * @param {Roo.Element} el
5936 * @param {Number} rowIndex
5937 * @param {Roo.EventObject} e
5941 * @event rowdblclick
5942 * Fires when a row is double clicked
5943 * @param {Roo.bootstrap.Table} this
5944 * @param {Roo.Element} el
5945 * @param {Number} rowIndex
5946 * @param {Roo.EventObject} e
5948 "rowdblclick" : true,
5951 * Fires when a mouseover occur
5952 * @param {Roo.bootstrap.Table} this
5953 * @param {Roo.Element} el
5954 * @param {Number} rowIndex
5955 * @param {Number} columnIndex
5956 * @param {Roo.EventObject} e
5961 * Fires when a mouseout occur
5962 * @param {Roo.bootstrap.Table} this
5963 * @param {Roo.Element} el
5964 * @param {Number} rowIndex
5965 * @param {Number} columnIndex
5966 * @param {Roo.EventObject} e
5971 * Fires when a row is rendered, so you can change add a style to it.
5972 * @param {Roo.bootstrap.Table} this
5973 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5977 * @event rowsrendered
5978 * Fires when all the rows have been rendered
5979 * @param {Roo.bootstrap.Table} this
5981 'rowsrendered' : true,
5983 * @event contextmenu
5984 * The raw contextmenu event for the entire grid.
5985 * @param {Roo.EventObject} e
5987 "contextmenu" : true,
5989 * @event rowcontextmenu
5990 * Fires when a row is right clicked
5991 * @param {Roo.bootstrap.Table} this
5992 * @param {Number} rowIndex
5993 * @param {Roo.EventObject} e
5995 "rowcontextmenu" : true,
5997 * @event cellcontextmenu
5998 * Fires when a cell is right clicked
5999 * @param {Roo.bootstrap.Table} this
6000 * @param {Number} rowIndex
6001 * @param {Number} cellIndex
6002 * @param {Roo.EventObject} e
6004 "cellcontextmenu" : true,
6006 * @event headercontextmenu
6007 * Fires when a header is right clicked
6008 * @param {Roo.bootstrap.Table} this
6009 * @param {Number} columnIndex
6010 * @param {Roo.EventObject} e
6012 "headercontextmenu" : true
6016 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6042 rowSelection : false,
6043 cellSelection : false,
6046 // Roo.Element - the tbody
6048 // Roo.Element - thead element
6051 container: false, // used by gridpanel...
6055 getAutoCreate : function()
6057 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6064 if (this.scrollBody) {
6065 cfg.cls += ' table-body-fixed';
6068 cfg.cls += ' table-striped';
6072 cfg.cls += ' table-hover';
6074 if (this.bordered) {
6075 cfg.cls += ' table-bordered';
6077 if (this.condensed) {
6078 cfg.cls += ' table-condensed';
6080 if (this.responsive) {
6081 cfg.cls += ' table-responsive';
6085 cfg.cls+= ' ' +this.cls;
6088 // this lot should be simplifed...
6091 cfg.align=this.align;
6094 cfg.bgcolor=this.bgcolor;
6097 cfg.border=this.border;
6099 if (this.cellpadding) {
6100 cfg.cellpadding=this.cellpadding;
6102 if (this.cellspacing) {
6103 cfg.cellspacing=this.cellspacing;
6106 cfg.frame=this.frame;
6109 cfg.rules=this.rules;
6111 if (this.sortable) {
6112 cfg.sortable=this.sortable;
6115 cfg.summary=this.summary;
6118 cfg.width=this.width;
6121 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6124 if(this.store || this.cm){
6125 if(this.headerShow){
6126 cfg.cn.push(this.renderHeader());
6129 cfg.cn.push(this.renderBody());
6131 if(this.footerShow){
6132 cfg.cn.push(this.renderFooter());
6134 // where does this come from?
6135 //cfg.cls+= ' TableGrid';
6138 return { cn : [ cfg ] };
6141 initEvents : function()
6143 if(!this.store || !this.cm){
6146 if (this.selModel) {
6147 this.selModel.initEvents();
6151 //Roo.log('initEvents with ds!!!!');
6153 this.mainBody = this.el.select('tbody', true).first();
6154 this.mainHead = this.el.select('thead', true).first();
6161 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6162 e.on('click', _this.sort, _this);
6165 this.mainBody.on("click", this.onClick, this);
6166 this.mainBody.on("dblclick", this.onDblClick, this);
6168 // why is this done????? = it breaks dialogs??
6169 //this.parent().el.setStyle('position', 'relative');
6173 this.footer.parentId = this.id;
6174 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6177 this.el.select('tfoot tr td').first().addClass('hide');
6181 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6183 this.store.on('load', this.onLoad, this);
6184 this.store.on('beforeload', this.onBeforeLoad, this);
6185 this.store.on('update', this.onUpdate, this);
6186 this.store.on('add', this.onAdd, this);
6187 this.store.on("clear", this.clear, this);
6189 this.el.on("contextmenu", this.onContextMenu, this);
6191 this.mainBody.on('scroll', this.onBodyScroll, this);
6193 this.cm.on("headerchange", this.onHeaderChange, this);
6197 onContextMenu : function(e, t)
6199 this.processEvent("contextmenu", e);
6202 processEvent : function(name, e)
6204 if (name != 'touchstart' ) {
6205 this.fireEvent(name, e);
6208 var t = e.getTarget();
6210 var cell = Roo.get(t);
6216 if(cell.findParent('tfoot', false, true)){
6220 if(cell.findParent('thead', false, true)){
6222 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6223 cell = Roo.get(t).findParent('th', false, true);
6225 Roo.log("failed to find th in thead?");
6226 Roo.log(e.getTarget());
6231 var cellIndex = cell.dom.cellIndex;
6233 var ename = name == 'touchstart' ? 'click' : name;
6234 this.fireEvent("header" + ename, this, cellIndex, e);
6239 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6240 cell = Roo.get(t).findParent('td', false, true);
6242 Roo.log("failed to find th in tbody?");
6243 Roo.log(e.getTarget());
6248 var row = cell.findParent('tr', false, true);
6249 var cellIndex = cell.dom.cellIndex;
6250 var rowIndex = row.dom.rowIndex - 1;
6254 this.fireEvent("row" + name, this, rowIndex, e);
6258 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6264 onMouseover : function(e, el)
6266 var cell = Roo.get(el);
6272 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6273 cell = cell.findParent('td', false, true);
6276 var row = cell.findParent('tr', false, true);
6277 var cellIndex = cell.dom.cellIndex;
6278 var rowIndex = row.dom.rowIndex - 1; // start from 0
6280 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6284 onMouseout : function(e, el)
6286 var cell = Roo.get(el);
6292 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6293 cell = cell.findParent('td', false, true);
6296 var row = cell.findParent('tr', false, true);
6297 var cellIndex = cell.dom.cellIndex;
6298 var rowIndex = row.dom.rowIndex - 1; // start from 0
6300 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6304 onClick : function(e, el)
6306 var cell = Roo.get(el);
6308 if(!cell || (!this.cellSelection && !this.rowSelection)){
6312 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6313 cell = cell.findParent('td', false, true);
6316 if(!cell || typeof(cell) == 'undefined'){
6320 var row = cell.findParent('tr', false, true);
6322 if(!row || typeof(row) == 'undefined'){
6326 var cellIndex = cell.dom.cellIndex;
6327 var rowIndex = this.getRowIndex(row);
6329 // why??? - should these not be based on SelectionModel?
6330 if(this.cellSelection){
6331 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6334 if(this.rowSelection){
6335 this.fireEvent('rowclick', this, row, rowIndex, e);
6341 onDblClick : function(e,el)
6343 var cell = Roo.get(el);
6345 if(!cell || (!this.cellSelection && !this.rowSelection)){
6349 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6350 cell = cell.findParent('td', false, true);
6353 if(!cell || typeof(cell) == 'undefined'){
6357 var row = cell.findParent('tr', false, true);
6359 if(!row || typeof(row) == 'undefined'){
6363 var cellIndex = cell.dom.cellIndex;
6364 var rowIndex = this.getRowIndex(row);
6366 if(this.cellSelection){
6367 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6370 if(this.rowSelection){
6371 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6375 sort : function(e,el)
6377 var col = Roo.get(el);
6379 if(!col.hasClass('sortable')){
6383 var sort = col.attr('sort');
6386 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6390 this.store.sortInfo = {field : sort, direction : dir};
6393 Roo.log("calling footer first");
6394 this.footer.onClick('first');
6397 this.store.load({ params : { start : 0 } });
6401 renderHeader : function()
6409 this.totalWidth = 0;
6411 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6413 var config = cm.config[i];
6418 html: cm.getColumnHeader(i)
6423 if(typeof(config.sortable) != 'undefined' && config.sortable){
6425 c.html = '<i class="glyphicon"></i>' + c.html;
6428 if(typeof(config.lgHeader) != 'undefined'){
6429 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6432 if(typeof(config.mdHeader) != 'undefined'){
6433 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6436 if(typeof(config.smHeader) != 'undefined'){
6437 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6440 if(typeof(config.xsHeader) != 'undefined'){
6441 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6448 if(typeof(config.tooltip) != 'undefined'){
6449 c.tooltip = config.tooltip;
6452 if(typeof(config.colspan) != 'undefined'){
6453 c.colspan = config.colspan;
6456 if(typeof(config.hidden) != 'undefined' && config.hidden){
6457 c.style += ' display:none;';
6460 if(typeof(config.dataIndex) != 'undefined'){
6461 c.sort = config.dataIndex;
6466 if(typeof(config.align) != 'undefined' && config.align.length){
6467 c.style += ' text-align:' + config.align + ';';
6470 if(typeof(config.width) != 'undefined'){
6471 c.style += ' width:' + config.width + 'px;';
6472 this.totalWidth += config.width;
6474 this.totalWidth += 100; // assume minimum of 100 per column?
6477 if(typeof(config.cls) != 'undefined'){
6478 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6481 ['xs','sm','md','lg'].map(function(size){
6483 if(typeof(config[size]) == 'undefined'){
6487 if (!config[size]) { // 0 = hidden
6488 c.cls += ' hidden-' + size;
6492 c.cls += ' col-' + size + '-' + config[size];
6502 renderBody : function()
6512 colspan : this.cm.getColumnCount()
6522 renderFooter : function()
6532 colspan : this.cm.getColumnCount()
6546 // Roo.log('ds onload');
6551 var ds = this.store;
6553 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6554 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6555 if (_this.store.sortInfo) {
6557 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6558 e.select('i', true).addClass(['glyphicon-arrow-up']);
6561 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6562 e.select('i', true).addClass(['glyphicon-arrow-down']);
6567 var tbody = this.mainBody;
6569 if(ds.getCount() > 0){
6570 ds.data.each(function(d,rowIndex){
6571 var row = this.renderRow(cm, ds, rowIndex);
6573 tbody.createChild(row);
6577 if(row.cellObjects.length){
6578 Roo.each(row.cellObjects, function(r){
6579 _this.renderCellObject(r);
6586 Roo.each(this.el.select('tbody td', true).elements, function(e){
6587 e.on('mouseover', _this.onMouseover, _this);
6590 Roo.each(this.el.select('tbody td', true).elements, function(e){
6591 e.on('mouseout', _this.onMouseout, _this);
6593 this.fireEvent('rowsrendered', this);
6594 //if(this.loadMask){
6595 // this.maskEl.hide();
6602 onUpdate : function(ds,record)
6604 this.refreshRow(record);
6608 onRemove : function(ds, record, index, isUpdate){
6609 if(isUpdate !== true){
6610 this.fireEvent("beforerowremoved", this, index, record);
6612 var bt = this.mainBody.dom;
6614 var rows = this.el.select('tbody > tr', true).elements;
6616 if(typeof(rows[index]) != 'undefined'){
6617 bt.removeChild(rows[index].dom);
6620 // if(bt.rows[index]){
6621 // bt.removeChild(bt.rows[index]);
6624 if(isUpdate !== true){
6625 //this.stripeRows(index);
6626 //this.syncRowHeights(index, index);
6628 this.fireEvent("rowremoved", this, index, record);
6632 onAdd : function(ds, records, rowIndex)
6634 //Roo.log('on Add called');
6635 // - note this does not handle multiple adding very well..
6636 var bt = this.mainBody.dom;
6637 for (var i =0 ; i < records.length;i++) {
6638 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6639 //Roo.log(records[i]);
6640 //Roo.log(this.store.getAt(rowIndex+i));
6641 this.insertRow(this.store, rowIndex + i, false);
6648 refreshRow : function(record){
6649 var ds = this.store, index;
6650 if(typeof record == 'number'){
6652 record = ds.getAt(index);
6654 index = ds.indexOf(record);
6656 this.insertRow(ds, index, true);
6658 this.onRemove(ds, record, index+1, true);
6660 //this.syncRowHeights(index, index);
6662 this.fireEvent("rowupdated", this, index, record);
6665 insertRow : function(dm, rowIndex, isUpdate){
6668 this.fireEvent("beforerowsinserted", this, rowIndex);
6670 //var s = this.getScrollState();
6671 var row = this.renderRow(this.cm, this.store, rowIndex);
6672 // insert before rowIndex..
6673 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6677 if(row.cellObjects.length){
6678 Roo.each(row.cellObjects, function(r){
6679 _this.renderCellObject(r);
6684 this.fireEvent("rowsinserted", this, rowIndex);
6685 //this.syncRowHeights(firstRow, lastRow);
6686 //this.stripeRows(firstRow);
6693 getRowDom : function(rowIndex)
6695 var rows = this.el.select('tbody > tr', true).elements;
6697 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6700 // returns the object tree for a tr..
6703 renderRow : function(cm, ds, rowIndex)
6706 var d = ds.getAt(rowIndex);
6713 var cellObjects = [];
6715 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6716 var config = cm.config[i];
6718 var renderer = cm.getRenderer(i);
6722 if(typeof(renderer) !== 'undefined'){
6723 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6725 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6726 // and are rendered into the cells after the row is rendered - using the id for the element.
6728 if(typeof(value) === 'object'){
6738 rowIndex : rowIndex,
6743 this.fireEvent('rowclass', this, rowcfg);
6747 cls : rowcfg.rowClass,
6749 html: (typeof(value) === 'object') ? '' : value
6756 if(typeof(config.colspan) != 'undefined'){
6757 td.colspan = config.colspan;
6760 if(typeof(config.hidden) != 'undefined' && config.hidden){
6761 td.style += ' display:none;';
6764 if(typeof(config.align) != 'undefined' && config.align.length){
6765 td.style += ' text-align:' + config.align + ';';
6768 if(typeof(config.width) != 'undefined'){
6769 td.style += ' width:' + config.width + 'px;';
6772 if(typeof(config.cursor) != 'undefined'){
6773 td.style += ' cursor:' + config.cursor + ';';
6776 if(typeof(config.cls) != 'undefined'){
6777 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6780 ['xs','sm','md','lg'].map(function(size){
6782 if(typeof(config[size]) == 'undefined'){
6786 if (!config[size]) { // 0 = hidden
6787 td.cls += ' hidden-' + size;
6791 td.cls += ' col-' + size + '-' + config[size];
6799 row.cellObjects = cellObjects;
6807 onBeforeLoad : function()
6809 //Roo.log('ds onBeforeLoad');
6813 //if(this.loadMask){
6814 // this.maskEl.show();
6822 this.el.select('tbody', true).first().dom.innerHTML = '';
6825 * Show or hide a row.
6826 * @param {Number} rowIndex to show or hide
6827 * @param {Boolean} state hide
6829 setRowVisibility : function(rowIndex, state)
6831 var bt = this.mainBody.dom;
6833 var rows = this.el.select('tbody > tr', true).elements;
6835 if(typeof(rows[rowIndex]) == 'undefined'){
6838 rows[rowIndex].dom.style.display = state ? '' : 'none';
6842 getSelectionModel : function(){
6844 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6846 return this.selModel;
6849 * Render the Roo.bootstrap object from renderder
6851 renderCellObject : function(r)
6855 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6857 var t = r.cfg.render(r.container);
6860 Roo.each(r.cfg.cn, function(c){
6862 container: t.getChildContainer(),
6865 _this.renderCellObject(child);
6870 getRowIndex : function(row)
6874 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6885 * Returns the grid's underlying element = used by panel.Grid
6886 * @return {Element} The element
6888 getGridEl : function(){
6892 * Forces a resize - used by panel.Grid
6893 * @return {Element} The element
6895 autoSize : function()
6897 //var ctr = Roo.get(this.container.dom.parentElement);
6898 var ctr = Roo.get(this.el.dom);
6900 var thd = this.getGridEl().select('thead',true).first();
6901 var tbd = this.getGridEl().select('tbody', true).first();
6902 var tfd = this.getGridEl().select('tfoot', true).first();
6904 var cw = ctr.getWidth();
6908 tbd.setSize(ctr.getWidth(),
6909 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6911 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6914 cw = Math.max(cw, this.totalWidth);
6915 this.getGridEl().select('tr',true).setWidth(cw);
6916 // resize 'expandable coloumn?
6918 return; // we doe not have a view in this design..
6921 onBodyScroll: function()
6923 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6925 this.mainHead.setStyle({
6926 'position' : 'relative',
6927 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6933 var scrollHeight = this.mainBody.dom.scrollHeight;
6935 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6937 var height = this.mainBody.getHeight();
6939 if(scrollHeight - height == scrollTop) {
6941 var total = this.ds.getTotalCount();
6943 if(this.footer.cursor + this.footer.pageSize < total){
6945 this.footer.ds.load({
6947 start : this.footer.cursor + this.footer.pageSize,
6948 limit : this.footer.pageSize
6958 onHeaderChange : function()
6961 var header = this.renderHeader();
6962 var table = this.el.select('table', true).first();
6964 this.mainHead.remove();
6965 this.mainHead = table.createChild(header, this.mainBody, false);
6980 * @class Roo.bootstrap.TableCell
6981 * @extends Roo.bootstrap.Component
6982 * Bootstrap TableCell class
6983 * @cfg {String} html cell contain text
6984 * @cfg {String} cls cell class
6985 * @cfg {String} tag cell tag (td|th) default td
6986 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6987 * @cfg {String} align Aligns the content in a cell
6988 * @cfg {String} axis Categorizes cells
6989 * @cfg {String} bgcolor Specifies the background color of a cell
6990 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6991 * @cfg {Number} colspan Specifies the number of columns a cell should span
6992 * @cfg {String} headers Specifies one or more header cells a cell is related to
6993 * @cfg {Number} height Sets the height of a cell
6994 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6995 * @cfg {Number} rowspan Sets the number of rows a cell should span
6996 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6997 * @cfg {String} valign Vertical aligns the content in a cell
6998 * @cfg {Number} width Specifies the width of a cell
7001 * Create a new TableCell
7002 * @param {Object} config The config object
7005 Roo.bootstrap.TableCell = function(config){
7006 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7009 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7029 getAutoCreate : function(){
7030 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7050 cfg.align=this.align
7056 cfg.bgcolor=this.bgcolor
7059 cfg.charoff=this.charoff
7062 cfg.colspan=this.colspan
7065 cfg.headers=this.headers
7068 cfg.height=this.height
7071 cfg.nowrap=this.nowrap
7074 cfg.rowspan=this.rowspan
7077 cfg.scope=this.scope
7080 cfg.valign=this.valign
7083 cfg.width=this.width
7102 * @class Roo.bootstrap.TableRow
7103 * @extends Roo.bootstrap.Component
7104 * Bootstrap TableRow class
7105 * @cfg {String} cls row class
7106 * @cfg {String} align Aligns the content in a table row
7107 * @cfg {String} bgcolor Specifies a background color for a table row
7108 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7109 * @cfg {String} valign Vertical aligns the content in a table row
7112 * Create a new TableRow
7113 * @param {Object} config The config object
7116 Roo.bootstrap.TableRow = function(config){
7117 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7120 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7128 getAutoCreate : function(){
7129 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7139 cfg.align = this.align;
7142 cfg.bgcolor = this.bgcolor;
7145 cfg.charoff = this.charoff;
7148 cfg.valign = this.valign;
7166 * @class Roo.bootstrap.TableBody
7167 * @extends Roo.bootstrap.Component
7168 * Bootstrap TableBody class
7169 * @cfg {String} cls element class
7170 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7171 * @cfg {String} align Aligns the content inside the element
7172 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7173 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7176 * Create a new TableBody
7177 * @param {Object} config The config object
7180 Roo.bootstrap.TableBody = function(config){
7181 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7184 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7192 getAutoCreate : function(){
7193 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7207 cfg.align = this.align;
7210 cfg.charoff = this.charoff;
7213 cfg.valign = this.valign;
7220 // initEvents : function()
7227 // this.store = Roo.factory(this.store, Roo.data);
7228 // this.store.on('load', this.onLoad, this);
7230 // this.store.load();
7234 // onLoad: function ()
7236 // this.fireEvent('load', this);
7246 * Ext JS Library 1.1.1
7247 * Copyright(c) 2006-2007, Ext JS, LLC.
7249 * Originally Released Under LGPL - original licence link has changed is not relivant.
7252 * <script type="text/javascript">
7255 // as we use this in bootstrap.
7256 Roo.namespace('Roo.form');
7258 * @class Roo.form.Action
7259 * Internal Class used to handle form actions
7261 * @param {Roo.form.BasicForm} el The form element or its id
7262 * @param {Object} config Configuration options
7267 // define the action interface
7268 Roo.form.Action = function(form, options){
7270 this.options = options || {};
7273 * Client Validation Failed
7276 Roo.form.Action.CLIENT_INVALID = 'client';
7278 * Server Validation Failed
7281 Roo.form.Action.SERVER_INVALID = 'server';
7283 * Connect to Server Failed
7286 Roo.form.Action.CONNECT_FAILURE = 'connect';
7288 * Reading Data from Server Failed
7291 Roo.form.Action.LOAD_FAILURE = 'load';
7293 Roo.form.Action.prototype = {
7295 failureType : undefined,
7296 response : undefined,
7300 run : function(options){
7305 success : function(response){
7310 handleResponse : function(response){
7314 // default connection failure
7315 failure : function(response){
7317 this.response = response;
7318 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7319 this.form.afterAction(this, false);
7322 processResponse : function(response){
7323 this.response = response;
7324 if(!response.responseText){
7327 this.result = this.handleResponse(response);
7331 // utility functions used internally
7332 getUrl : function(appendParams){
7333 var url = this.options.url || this.form.url || this.form.el.dom.action;
7335 var p = this.getParams();
7337 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7343 getMethod : function(){
7344 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7347 getParams : function(){
7348 var bp = this.form.baseParams;
7349 var p = this.options.params;
7351 if(typeof p == "object"){
7352 p = Roo.urlEncode(Roo.applyIf(p, bp));
7353 }else if(typeof p == 'string' && bp){
7354 p += '&' + Roo.urlEncode(bp);
7357 p = Roo.urlEncode(bp);
7362 createCallback : function(){
7364 success: this.success,
7365 failure: this.failure,
7367 timeout: (this.form.timeout*1000),
7368 upload: this.form.fileUpload ? this.success : undefined
7373 Roo.form.Action.Submit = function(form, options){
7374 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7377 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7380 haveProgress : false,
7381 uploadComplete : false,
7383 // uploadProgress indicator.
7384 uploadProgress : function()
7386 if (!this.form.progressUrl) {
7390 if (!this.haveProgress) {
7391 Roo.MessageBox.progress("Uploading", "Uploading");
7393 if (this.uploadComplete) {
7394 Roo.MessageBox.hide();
7398 this.haveProgress = true;
7400 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7402 var c = new Roo.data.Connection();
7404 url : this.form.progressUrl,
7409 success : function(req){
7410 //console.log(data);
7414 rdata = Roo.decode(req.responseText)
7416 Roo.log("Invalid data from server..");
7420 if (!rdata || !rdata.success) {
7422 Roo.MessageBox.alert(Roo.encode(rdata));
7425 var data = rdata.data;
7427 if (this.uploadComplete) {
7428 Roo.MessageBox.hide();
7433 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7434 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7437 this.uploadProgress.defer(2000,this);
7440 failure: function(data) {
7441 Roo.log('progress url failed ');
7452 // run get Values on the form, so it syncs any secondary forms.
7453 this.form.getValues();
7455 var o = this.options;
7456 var method = this.getMethod();
7457 var isPost = method == 'POST';
7458 if(o.clientValidation === false || this.form.isValid()){
7460 if (this.form.progressUrl) {
7461 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7462 (new Date() * 1) + '' + Math.random());
7467 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7468 form:this.form.el.dom,
7469 url:this.getUrl(!isPost),
7471 params:isPost ? this.getParams() : null,
7472 isUpload: this.form.fileUpload
7475 this.uploadProgress();
7477 }else if (o.clientValidation !== false){ // client validation failed
7478 this.failureType = Roo.form.Action.CLIENT_INVALID;
7479 this.form.afterAction(this, false);
7483 success : function(response)
7485 this.uploadComplete= true;
7486 if (this.haveProgress) {
7487 Roo.MessageBox.hide();
7491 var result = this.processResponse(response);
7492 if(result === true || result.success){
7493 this.form.afterAction(this, true);
7497 this.form.markInvalid(result.errors);
7498 this.failureType = Roo.form.Action.SERVER_INVALID;
7500 this.form.afterAction(this, false);
7502 failure : function(response)
7504 this.uploadComplete= true;
7505 if (this.haveProgress) {
7506 Roo.MessageBox.hide();
7509 this.response = response;
7510 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7511 this.form.afterAction(this, false);
7514 handleResponse : function(response){
7515 if(this.form.errorReader){
7516 var rs = this.form.errorReader.read(response);
7519 for(var i = 0, len = rs.records.length; i < len; i++) {
7520 var r = rs.records[i];
7524 if(errors.length < 1){
7528 success : rs.success,
7534 ret = Roo.decode(response.responseText);
7538 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7548 Roo.form.Action.Load = function(form, options){
7549 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7550 this.reader = this.form.reader;
7553 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7558 Roo.Ajax.request(Roo.apply(
7559 this.createCallback(), {
7560 method:this.getMethod(),
7561 url:this.getUrl(false),
7562 params:this.getParams()
7566 success : function(response){
7568 var result = this.processResponse(response);
7569 if(result === true || !result.success || !result.data){
7570 this.failureType = Roo.form.Action.LOAD_FAILURE;
7571 this.form.afterAction(this, false);
7574 this.form.clearInvalid();
7575 this.form.setValues(result.data);
7576 this.form.afterAction(this, true);
7579 handleResponse : function(response){
7580 if(this.form.reader){
7581 var rs = this.form.reader.read(response);
7582 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7584 success : rs.success,
7588 return Roo.decode(response.responseText);
7592 Roo.form.Action.ACTION_TYPES = {
7593 'load' : Roo.form.Action.Load,
7594 'submit' : Roo.form.Action.Submit
7603 * @class Roo.bootstrap.Form
7604 * @extends Roo.bootstrap.Component
7605 * Bootstrap Form class
7606 * @cfg {String} method GET | POST (default POST)
7607 * @cfg {String} labelAlign top | left (default top)
7608 * @cfg {String} align left | right - for navbars
7609 * @cfg {Boolean} loadMask load mask when submit (default true)
7614 * @param {Object} config The config object
7618 Roo.bootstrap.Form = function(config){
7620 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7622 Roo.bootstrap.Form.popover.apply();
7626 * @event clientvalidation
7627 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7628 * @param {Form} this
7629 * @param {Boolean} valid true if the form has passed client-side validation
7631 clientvalidation: true,
7633 * @event beforeaction
7634 * Fires before any action is performed. Return false to cancel the action.
7635 * @param {Form} this
7636 * @param {Action} action The action to be performed
7640 * @event actionfailed
7641 * Fires when an action fails.
7642 * @param {Form} this
7643 * @param {Action} action The action that failed
7645 actionfailed : true,
7647 * @event actioncomplete
7648 * Fires when an action is completed.
7649 * @param {Form} this
7650 * @param {Action} action The action that completed
7652 actioncomplete : true
7656 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7659 * @cfg {String} method
7660 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7665 * The URL to use for form actions if one isn't supplied in the action options.
7668 * @cfg {Boolean} fileUpload
7669 * Set to true if this form is a file upload.
7673 * @cfg {Object} baseParams
7674 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7678 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7682 * @cfg {Sting} align (left|right) for navbar forms
7687 activeAction : null,
7690 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7691 * element by passing it or its id or mask the form itself by passing in true.
7694 waitMsgTarget : false,
7699 * @cfg {Boolean} errorMask (true|false) default false
7704 * @cfg {Number} maskOffset Default 100
7709 * @cfg {Boolean} maskBody
7713 getAutoCreate : function(){
7717 method : this.method || 'POST',
7718 id : this.id || Roo.id(),
7721 if (this.parent().xtype.match(/^Nav/)) {
7722 cfg.cls = 'navbar-form navbar-' + this.align;
7726 if (this.labelAlign == 'left' ) {
7727 cfg.cls += ' form-horizontal';
7733 initEvents : function()
7735 this.el.on('submit', this.onSubmit, this);
7736 // this was added as random key presses on the form where triggering form submit.
7737 this.el.on('keypress', function(e) {
7738 if (e.getCharCode() != 13) {
7741 // we might need to allow it for textareas.. and some other items.
7742 // check e.getTarget().
7744 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7748 Roo.log("keypress blocked");
7756 onSubmit : function(e){
7761 * Returns true if client-side validation on the form is successful.
7764 isValid : function(){
7765 var items = this.getItems();
7769 items.each(function(f){
7775 if(!target && f.el.isVisible(true)){
7781 if(this.errorMask && !valid){
7782 Roo.bootstrap.Form.popover.mask(this, target);
7789 * Returns true if any fields in this form have changed since their original load.
7792 isDirty : function(){
7794 var items = this.getItems();
7795 items.each(function(f){
7805 * Performs a predefined action (submit or load) or custom actions you define on this form.
7806 * @param {String} actionName The name of the action type
7807 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7808 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7809 * accept other config options):
7811 Property Type Description
7812 ---------------- --------------- ----------------------------------------------------------------------------------
7813 url String The url for the action (defaults to the form's url)
7814 method String The form method to use (defaults to the form's method, or POST if not defined)
7815 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7816 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7817 validate the form on the client (defaults to false)
7819 * @return {BasicForm} this
7821 doAction : function(action, options){
7822 if(typeof action == 'string'){
7823 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7825 if(this.fireEvent('beforeaction', this, action) !== false){
7826 this.beforeAction(action);
7827 action.run.defer(100, action);
7833 beforeAction : function(action){
7834 var o = action.options;
7839 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7841 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7844 // not really supported yet.. ??
7846 //if(this.waitMsgTarget === true){
7847 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7848 //}else if(this.waitMsgTarget){
7849 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7850 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7852 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7858 afterAction : function(action, success){
7859 this.activeAction = null;
7860 var o = action.options;
7865 Roo.get(document.body).unmask();
7871 //if(this.waitMsgTarget === true){
7872 // this.el.unmask();
7873 //}else if(this.waitMsgTarget){
7874 // this.waitMsgTarget.unmask();
7876 // Roo.MessageBox.updateProgress(1);
7877 // Roo.MessageBox.hide();
7884 Roo.callback(o.success, o.scope, [this, action]);
7885 this.fireEvent('actioncomplete', this, action);
7889 // failure condition..
7890 // we have a scenario where updates need confirming.
7891 // eg. if a locking scenario exists..
7892 // we look for { errors : { needs_confirm : true }} in the response.
7894 (typeof(action.result) != 'undefined') &&
7895 (typeof(action.result.errors) != 'undefined') &&
7896 (typeof(action.result.errors.needs_confirm) != 'undefined')
7899 Roo.log("not supported yet");
7902 Roo.MessageBox.confirm(
7903 "Change requires confirmation",
7904 action.result.errorMsg,
7909 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7919 Roo.callback(o.failure, o.scope, [this, action]);
7920 // show an error message if no failed handler is set..
7921 if (!this.hasListener('actionfailed')) {
7922 Roo.log("need to add dialog support");
7924 Roo.MessageBox.alert("Error",
7925 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7926 action.result.errorMsg :
7927 "Saving Failed, please check your entries or try again"
7932 this.fireEvent('actionfailed', this, action);
7937 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7938 * @param {String} id The value to search for
7941 findField : function(id){
7942 var items = this.getItems();
7943 var field = items.get(id);
7945 items.each(function(f){
7946 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7953 return field || null;
7956 * Mark fields in this form invalid in bulk.
7957 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7958 * @return {BasicForm} this
7960 markInvalid : function(errors){
7961 if(errors instanceof Array){
7962 for(var i = 0, len = errors.length; i < len; i++){
7963 var fieldError = errors[i];
7964 var f = this.findField(fieldError.id);
7966 f.markInvalid(fieldError.msg);
7972 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7973 field.markInvalid(errors[id]);
7977 //Roo.each(this.childForms || [], function (f) {
7978 // f.markInvalid(errors);
7985 * Set values for fields in this form in bulk.
7986 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7987 * @return {BasicForm} this
7989 setValues : function(values){
7990 if(values instanceof Array){ // array of objects
7991 for(var i = 0, len = values.length; i < len; i++){
7993 var f = this.findField(v.id);
7995 f.setValue(v.value);
7996 if(this.trackResetOnLoad){
7997 f.originalValue = f.getValue();
8001 }else{ // object hash
8004 if(typeof values[id] != 'function' && (field = this.findField(id))){
8006 if (field.setFromData &&
8008 field.displayField &&
8009 // combos' with local stores can
8010 // be queried via setValue()
8011 // to set their value..
8012 (field.store && !field.store.isLocal)
8016 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8017 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8018 field.setFromData(sd);
8020 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8022 field.setFromData(values);
8025 field.setValue(values[id]);
8029 if(this.trackResetOnLoad){
8030 field.originalValue = field.getValue();
8036 //Roo.each(this.childForms || [], function (f) {
8037 // f.setValues(values);
8044 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8045 * they are returned as an array.
8046 * @param {Boolean} asString
8049 getValues : function(asString){
8050 //if (this.childForms) {
8051 // copy values from the child forms
8052 // Roo.each(this.childForms, function (f) {
8053 // this.setValues(f.getValues());
8059 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8060 if(asString === true){
8063 return Roo.urlDecode(fs);
8067 * Returns the fields in this form as an object with key/value pairs.
8068 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8071 getFieldValues : function(with_hidden)
8073 var items = this.getItems();
8075 items.each(function(f){
8081 var v = f.getValue();
8083 if (f.inputType =='radio') {
8084 if (typeof(ret[f.getName()]) == 'undefined') {
8085 ret[f.getName()] = ''; // empty..
8088 if (!f.el.dom.checked) {
8096 if(f.xtype == 'MoneyField'){
8097 ret[f.currencyName] = f.getCurrency();
8100 // not sure if this supported any more..
8101 if ((typeof(v) == 'object') && f.getRawValue) {
8102 v = f.getRawValue() ; // dates..
8104 // combo boxes where name != hiddenName...
8105 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8106 ret[f.name] = f.getRawValue();
8108 ret[f.getName()] = v;
8115 * Clears all invalid messages in this form.
8116 * @return {BasicForm} this
8118 clearInvalid : function(){
8119 var items = this.getItems();
8121 items.each(function(f){
8130 * @return {BasicForm} this
8133 var items = this.getItems();
8134 items.each(function(f){
8138 Roo.each(this.childForms || [], function (f) {
8146 getItems : function()
8148 var r=new Roo.util.MixedCollection(false, function(o){
8149 return o.id || (o.id = Roo.id());
8151 var iter = function(el) {
8158 Roo.each(el.items,function(e) {
8167 hideFields : function(items)
8169 Roo.each(items, function(i){
8171 var f = this.findField(i);
8177 if(f.xtype == 'DateField'){
8178 f.setVisible(false);
8187 showFields : function(items)
8189 Roo.each(items, function(i){
8191 var f = this.findField(i);
8197 if(f.xtype == 'DateField'){
8209 Roo.apply(Roo.bootstrap.Form, {
8236 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8237 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8238 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8239 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8242 this.maskEl.top.enableDisplayMode("block");
8243 this.maskEl.left.enableDisplayMode("block");
8244 this.maskEl.bottom.enableDisplayMode("block");
8245 this.maskEl.right.enableDisplayMode("block");
8247 this.toolTip = new Roo.bootstrap.Tooltip({
8248 cls : 'roo-form-error-popover',
8250 'left' : ['r-l', [-2,0], 'right'],
8251 'right' : ['l-r', [2,0], 'left'],
8252 'bottom' : ['tl-bl', [0,2], 'top'],
8253 'top' : [ 'bl-tl', [0,-2], 'bottom']
8257 this.toolTip.render(Roo.get(document.body));
8259 this.toolTip.el.enableDisplayMode("block");
8261 Roo.get(document.body).on('click', function(){
8265 Roo.get(document.body).on('touchstart', function(){
8269 this.isApplied = true
8272 mask : function(form, target)
8276 this.target = target;
8278 if(!this.form.errorMask || !target.el){
8282 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8284 Roo.log(scrollable);
8286 var ot = this.target.el.calcOffsetsTo(scrollable);
8288 var scrollTo = ot[1] - this.form.maskOffset;
8290 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8292 scrollable.scrollTo('top', scrollTo);
8294 var box = this.target.el.getBox();
8296 var zIndex = Roo.bootstrap.Modal.zIndex++;
8299 this.maskEl.top.setStyle('position', 'absolute');
8300 this.maskEl.top.setStyle('z-index', zIndex);
8301 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8302 this.maskEl.top.setLeft(0);
8303 this.maskEl.top.setTop(0);
8304 this.maskEl.top.show();
8306 this.maskEl.left.setStyle('position', 'absolute');
8307 this.maskEl.left.setStyle('z-index', zIndex);
8308 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8309 this.maskEl.left.setLeft(0);
8310 this.maskEl.left.setTop(box.y - this.padding);
8311 this.maskEl.left.show();
8313 this.maskEl.bottom.setStyle('position', 'absolute');
8314 this.maskEl.bottom.setStyle('z-index', zIndex);
8315 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8316 this.maskEl.bottom.setLeft(0);
8317 this.maskEl.bottom.setTop(box.bottom + this.padding);
8318 this.maskEl.bottom.show();
8320 this.maskEl.right.setStyle('position', 'absolute');
8321 this.maskEl.right.setStyle('z-index', zIndex);
8322 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8323 this.maskEl.right.setLeft(box.right + this.padding);
8324 this.maskEl.right.setTop(box.y - this.padding);
8325 this.maskEl.right.show();
8327 this.toolTip.bindEl = this.target.el;
8329 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8331 var tip = this.target.blankText;
8333 if(this.target.getValue() !== '' ) {
8335 if (this.target.invalidText.length) {
8336 tip = this.target.invalidText;
8337 } else if (this.target.regexText.length){
8338 tip = this.target.regexText;
8342 this.toolTip.show(tip);
8344 this.intervalID = window.setInterval(function() {
8345 Roo.bootstrap.Form.popover.unmask();
8348 window.onwheel = function(){ return false;};
8350 (function(){ this.isMasked = true; }).defer(500, this);
8356 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8360 this.maskEl.top.setStyle('position', 'absolute');
8361 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8362 this.maskEl.top.hide();
8364 this.maskEl.left.setStyle('position', 'absolute');
8365 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8366 this.maskEl.left.hide();
8368 this.maskEl.bottom.setStyle('position', 'absolute');
8369 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8370 this.maskEl.bottom.hide();
8372 this.maskEl.right.setStyle('position', 'absolute');
8373 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8374 this.maskEl.right.hide();
8376 this.toolTip.hide();
8378 this.toolTip.el.hide();
8380 window.onwheel = function(){ return true;};
8382 if(this.intervalID){
8383 window.clearInterval(this.intervalID);
8384 this.intervalID = false;
8387 this.isMasked = false;
8397 * Ext JS Library 1.1.1
8398 * Copyright(c) 2006-2007, Ext JS, LLC.
8400 * Originally Released Under LGPL - original licence link has changed is not relivant.
8403 * <script type="text/javascript">
8406 * @class Roo.form.VTypes
8407 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8410 Roo.form.VTypes = function(){
8411 // closure these in so they are only created once.
8412 var alpha = /^[a-zA-Z_]+$/;
8413 var alphanum = /^[a-zA-Z0-9_]+$/;
8414 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8415 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8417 // All these messages and functions are configurable
8420 * The function used to validate email addresses
8421 * @param {String} value The email address
8423 'email' : function(v){
8424 return email.test(v);
8427 * The error text to display when the email validation function returns false
8430 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8432 * The keystroke filter mask to be applied on email input
8435 'emailMask' : /[a-z0-9_\.\-@]/i,
8438 * The function used to validate URLs
8439 * @param {String} value The URL
8441 'url' : function(v){
8445 * The error text to display when the url validation function returns false
8448 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8451 * The function used to validate alpha values
8452 * @param {String} value The value
8454 'alpha' : function(v){
8455 return alpha.test(v);
8458 * The error text to display when the alpha validation function returns false
8461 'alphaText' : 'This field should only contain letters and _',
8463 * The keystroke filter mask to be applied on alpha input
8466 'alphaMask' : /[a-z_]/i,
8469 * The function used to validate alphanumeric values
8470 * @param {String} value The value
8472 'alphanum' : function(v){
8473 return alphanum.test(v);
8476 * The error text to display when the alphanumeric validation function returns false
8479 'alphanumText' : 'This field should only contain letters, numbers and _',
8481 * The keystroke filter mask to be applied on alphanumeric input
8484 'alphanumMask' : /[a-z0-9_]/i
8494 * @class Roo.bootstrap.Input
8495 * @extends Roo.bootstrap.Component
8496 * Bootstrap Input class
8497 * @cfg {Boolean} disabled is it disabled
8498 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8499 * @cfg {String} name name of the input
8500 * @cfg {string} fieldLabel - the label associated
8501 * @cfg {string} placeholder - placeholder to put in text.
8502 * @cfg {string} before - input group add on before
8503 * @cfg {string} after - input group add on after
8504 * @cfg {string} size - (lg|sm) or leave empty..
8505 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8506 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8507 * @cfg {Number} md colspan out of 12 for computer-sized screens
8508 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8509 * @cfg {string} value default value of the input
8510 * @cfg {Number} labelWidth set the width of label
8511 * @cfg {Number} labellg set the width of label (1-12)
8512 * @cfg {Number} labelmd set the width of label (1-12)
8513 * @cfg {Number} labelsm set the width of label (1-12)
8514 * @cfg {Number} labelxs set the width of label (1-12)
8515 * @cfg {String} labelAlign (top|left)
8516 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8517 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8518 * @cfg {String} indicatorpos (left|right) default left
8520 * @cfg {String} align (left|center|right) Default left
8521 * @cfg {Boolean} forceFeedback (true|false) Default false
8522 * @cfg {Boolean} hideParent (true|false) Default false also hide the parent
8527 * Create a new Input
8528 * @param {Object} config The config object
8531 Roo.bootstrap.Input = function(config){
8533 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8538 * Fires when this field receives input focus.
8539 * @param {Roo.form.Field} this
8544 * Fires when this field loses input focus.
8545 * @param {Roo.form.Field} this
8550 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8551 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8552 * @param {Roo.form.Field} this
8553 * @param {Roo.EventObject} e The event object
8558 * Fires just before the field blurs if the field value has changed.
8559 * @param {Roo.form.Field} this
8560 * @param {Mixed} newValue The new value
8561 * @param {Mixed} oldValue The original value
8566 * Fires after the field has been marked as invalid.
8567 * @param {Roo.form.Field} this
8568 * @param {String} msg The validation message
8573 * Fires after the field has been validated with no errors.
8574 * @param {Roo.form.Field} this
8579 * Fires after the key up
8580 * @param {Roo.form.Field} this
8581 * @param {Roo.EventObject} e The event Object
8587 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8589 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8590 automatic validation (defaults to "keyup").
8592 validationEvent : "keyup",
8594 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8596 validateOnBlur : true,
8598 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8600 validationDelay : 250,
8602 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8604 focusClass : "x-form-focus", // not needed???
8608 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8610 invalidClass : "has-warning",
8613 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8615 validClass : "has-success",
8618 * @cfg {Boolean} hasFeedback (true|false) default true
8623 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8625 invalidFeedbackClass : "glyphicon-warning-sign",
8628 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8630 validFeedbackClass : "glyphicon-ok",
8633 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8635 selectOnFocus : false,
8638 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8642 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8647 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8649 disableKeyFilter : false,
8652 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8656 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8660 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8662 blankText : "Please complete this mandatory field",
8665 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8669 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8671 maxLength : Number.MAX_VALUE,
8673 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8675 minLengthText : "The minimum length for this field is {0}",
8677 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8679 maxLengthText : "The maximum length for this field is {0}",
8683 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8684 * If available, this function will be called only after the basic validators all return true, and will be passed the
8685 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8689 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8690 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8691 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8695 * @cfg {String} regexText -- Depricated - use Invalid Text
8700 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8706 autocomplete: false,
8725 formatedValue : false,
8726 forceFeedback : false,
8728 indicatorpos : 'left',
8737 parentLabelAlign : function()
8740 while (parent.parent()) {
8741 parent = parent.parent();
8742 if (typeof(parent.labelAlign) !='undefined') {
8743 return parent.labelAlign;
8750 getAutoCreate : function()
8752 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8758 if(this.inputType != 'hidden'){
8759 cfg.cls = 'form-group' //input-group
8765 type : this.inputType,
8767 cls : 'form-control',
8768 placeholder : this.placeholder || '',
8769 autocomplete : this.autocomplete || 'new-password'
8773 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8776 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8777 input.maxLength = this.maxLength;
8780 if (this.disabled) {
8781 input.disabled=true;
8784 if (this.readOnly) {
8785 input.readonly=true;
8789 input.name = this.name;
8793 input.cls += ' input-' + this.size;
8797 ['xs','sm','md','lg'].map(function(size){
8798 if (settings[size]) {
8799 cfg.cls += ' col-' + size + '-' + settings[size];
8803 var inputblock = input;
8807 cls: 'glyphicon form-control-feedback'
8810 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8813 cls : 'has-feedback',
8821 if (this.before || this.after) {
8824 cls : 'input-group',
8828 if (this.before && typeof(this.before) == 'string') {
8830 inputblock.cn.push({
8832 cls : 'roo-input-before input-group-addon',
8836 if (this.before && typeof(this.before) == 'object') {
8837 this.before = Roo.factory(this.before);
8839 inputblock.cn.push({
8841 cls : 'roo-input-before input-group-' +
8842 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8846 inputblock.cn.push(input);
8848 if (this.after && typeof(this.after) == 'string') {
8849 inputblock.cn.push({
8851 cls : 'roo-input-after input-group-addon',
8855 if (this.after && typeof(this.after) == 'object') {
8856 this.after = Roo.factory(this.after);
8858 inputblock.cn.push({
8860 cls : 'roo-input-after input-group-' +
8861 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8865 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8866 inputblock.cls += ' has-feedback';
8867 inputblock.cn.push(feedback);
8871 if (align ==='left' && this.fieldLabel.length) {
8873 cfg.cls += ' roo-form-group-label-left';
8878 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8879 tooltip : 'This field is required'
8884 cls : 'control-label',
8885 html : this.fieldLabel
8896 var labelCfg = cfg.cn[1];
8897 var contentCfg = cfg.cn[2];
8899 if(this.indicatorpos == 'right'){
8904 cls : 'control-label',
8908 html : this.fieldLabel
8912 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8913 tooltip : 'This field is required'
8926 labelCfg = cfg.cn[0];
8927 contentCfg = cfg.cn[1];
8931 if(this.labelWidth > 12){
8932 labelCfg.style = "width: " + this.labelWidth + 'px';
8935 if(this.labelWidth < 13 && this.labelmd == 0){
8936 this.labelmd = this.labelWidth;
8939 if(this.labellg > 0){
8940 labelCfg.cls += ' col-lg-' + this.labellg;
8941 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8944 if(this.labelmd > 0){
8945 labelCfg.cls += ' col-md-' + this.labelmd;
8946 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8949 if(this.labelsm > 0){
8950 labelCfg.cls += ' col-sm-' + this.labelsm;
8951 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8954 if(this.labelxs > 0){
8955 labelCfg.cls += ' col-xs-' + this.labelxs;
8956 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8960 } else if ( this.fieldLabel.length) {
8965 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8966 tooltip : 'This field is required'
8970 //cls : 'input-group-addon',
8971 html : this.fieldLabel
8979 if(this.indicatorpos == 'right'){
8984 //cls : 'input-group-addon',
8985 html : this.fieldLabel
8990 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8991 tooltip : 'This field is required'
9011 if (this.parentType === 'Navbar' && this.parent().bar) {
9012 cfg.cls += ' navbar-form';
9015 if (this.parentType === 'NavGroup') {
9016 cfg.cls += ' navbar-form';
9024 * return the real input element.
9026 inputEl: function ()
9028 return this.el.select('input.form-control',true).first();
9031 tooltipEl : function()
9033 return this.inputEl();
9036 indicatorEl : function()
9038 var indicator = this.el.select('i.roo-required-indicator',true).first();
9048 setDisabled : function(v)
9050 var i = this.inputEl().dom;
9052 i.removeAttribute('disabled');
9056 i.setAttribute('disabled','true');
9058 initEvents : function()
9061 this.inputEl().on("keydown" , this.fireKey, this);
9062 this.inputEl().on("focus", this.onFocus, this);
9063 this.inputEl().on("blur", this.onBlur, this);
9065 this.inputEl().relayEvent('keyup', this);
9067 this.indicator = this.indicatorEl();
9070 this.indicator.addClass('invisible');
9074 // reference to original value for reset
9075 this.originalValue = this.getValue();
9076 //Roo.form.TextField.superclass.initEvents.call(this);
9077 if(this.validationEvent == 'keyup'){
9078 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9079 this.inputEl().on('keyup', this.filterValidation, this);
9081 else if(this.validationEvent !== false){
9082 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9085 if(this.selectOnFocus){
9086 this.on("focus", this.preFocus, this);
9089 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9090 this.inputEl().on("keypress", this.filterKeys, this);
9092 this.inputEl().relayEvent('keypress', this);
9095 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9096 this.el.on("click", this.autoSize, this);
9099 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9100 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9103 if (typeof(this.before) == 'object') {
9104 this.before.render(this.el.select('.roo-input-before',true).first());
9106 if (typeof(this.after) == 'object') {
9107 this.after.render(this.el.select('.roo-input-after',true).first());
9112 filterValidation : function(e){
9113 if(!e.isNavKeyPress()){
9114 this.validationTask.delay(this.validationDelay);
9118 * Validates the field value
9119 * @return {Boolean} True if the value is valid, else false
9121 validate : function(){
9122 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9123 if(this.disabled || this.validateValue(this.getRawValue())){
9134 * Validates a value according to the field's validation rules and marks the field as invalid
9135 * if the validation fails
9136 * @param {Mixed} value The value to validate
9137 * @return {Boolean} True if the value is valid, else false
9139 validateValue : function(value)
9141 if(this.getEl().hasClass('hidden') || !this.inputEl().isVisible(true)){
9145 if(value.length < 1) { // if it's blank
9146 if(this.allowBlank){
9152 if(value.length < this.minLength){
9155 if(value.length > this.maxLength){
9159 var vt = Roo.form.VTypes;
9160 if(!vt[this.vtype](value, this)){
9164 if(typeof this.validator == "function"){
9165 var msg = this.validator(value);
9169 if (typeof(msg) == 'string') {
9170 this.invalidText = msg;
9174 if(this.regex && !this.regex.test(value)){
9182 fireKey : function(e){
9183 //Roo.log('field ' + e.getKey());
9184 if(e.isNavKeyPress()){
9185 this.fireEvent("specialkey", this, e);
9188 focus : function (selectText){
9190 this.inputEl().focus();
9191 if(selectText === true){
9192 this.inputEl().dom.select();
9198 onFocus : function(){
9199 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9200 // this.el.addClass(this.focusClass);
9203 this.hasFocus = true;
9204 this.startValue = this.getValue();
9205 this.fireEvent("focus", this);
9209 beforeBlur : Roo.emptyFn,
9213 onBlur : function(){
9215 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9216 //this.el.removeClass(this.focusClass);
9218 this.hasFocus = false;
9219 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9222 var v = this.getValue();
9223 if(String(v) !== String(this.startValue)){
9224 this.fireEvent('change', this, v, this.startValue);
9226 this.fireEvent("blur", this);
9230 * Resets the current field value to the originally loaded value and clears any validation messages
9233 this.setValue(this.originalValue);
9237 * Returns the name of the field
9238 * @return {Mixed} name The name field
9240 getName: function(){
9244 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9245 * @return {Mixed} value The field value
9247 getValue : function(){
9249 var v = this.inputEl().getValue();
9254 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9255 * @return {Mixed} value The field value
9257 getRawValue : function(){
9258 var v = this.inputEl().getValue();
9264 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9265 * @param {Mixed} value The value to set
9267 setRawValue : function(v){
9268 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9271 selectText : function(start, end){
9272 var v = this.getRawValue();
9274 start = start === undefined ? 0 : start;
9275 end = end === undefined ? v.length : end;
9276 var d = this.inputEl().dom;
9277 if(d.setSelectionRange){
9278 d.setSelectionRange(start, end);
9279 }else if(d.createTextRange){
9280 var range = d.createTextRange();
9281 range.moveStart("character", start);
9282 range.moveEnd("character", v.length-end);
9289 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9290 * @param {Mixed} value The value to set
9292 setValue : function(v){
9295 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9301 processValue : function(value){
9302 if(this.stripCharsRe){
9303 var newValue = value.replace(this.stripCharsRe, '');
9304 if(newValue !== value){
9305 this.setRawValue(newValue);
9312 preFocus : function(){
9314 if(this.selectOnFocus){
9315 this.inputEl().dom.select();
9318 filterKeys : function(e){
9320 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9323 var c = e.getCharCode(), cc = String.fromCharCode(c);
9324 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9327 if(!this.maskRe.test(cc)){
9332 * Clear any invalid styles/messages for this field
9334 clearInvalid : function(){
9336 if(!this.el || this.preventMark){ // not rendered
9341 this.el.removeClass(this.invalidClass);
9343 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9345 var feedback = this.el.select('.form-control-feedback', true).first();
9348 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9353 this.fireEvent('valid', this);
9357 * Mark this field as valid
9359 markValid : function()
9361 if(!this.el || this.preventMark){ // not rendered...
9365 this.el.removeClass([this.invalidClass, this.validClass]);
9367 var feedback = this.el.select('.form-control-feedback', true).first();
9370 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9374 this.indicator.removeClass('visible');
9375 this.indicator.addClass('invisible');
9382 if(this.allowBlank && !this.getRawValue().length){
9386 this.el.addClass(this.validClass);
9388 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9390 var feedback = this.el.select('.form-control-feedback', true).first();
9393 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9394 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9399 this.fireEvent('valid', this);
9403 * Mark this field as invalid
9404 * @param {String} msg The validation message
9406 markInvalid : function(msg)
9408 if(!this.el || this.preventMark){ // not rendered
9412 this.el.removeClass([this.invalidClass, this.validClass]);
9414 var feedback = this.el.select('.form-control-feedback', true).first();
9417 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9424 if(this.allowBlank && !this.getRawValue().length){
9429 this.indicator.removeClass('invisible');
9430 this.indicator.addClass('visible');
9433 this.el.addClass(this.invalidClass);
9435 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9437 var feedback = this.el.select('.form-control-feedback', true).first();
9440 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9442 if(this.getValue().length || this.forceFeedback){
9443 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9450 this.fireEvent('invalid', this, msg);
9453 SafariOnKeyDown : function(event)
9455 // this is a workaround for a password hang bug on chrome/ webkit.
9456 if (this.inputEl().dom.type != 'password') {
9460 var isSelectAll = false;
9462 if(this.inputEl().dom.selectionEnd > 0){
9463 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9465 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9466 event.preventDefault();
9471 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9473 event.preventDefault();
9474 // this is very hacky as keydown always get's upper case.
9476 var cc = String.fromCharCode(event.getCharCode());
9477 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9481 adjustWidth : function(tag, w){
9482 tag = tag.toLowerCase();
9483 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9484 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9488 if(tag == 'textarea'){
9491 }else if(Roo.isOpera){
9495 if(tag == 'textarea'){
9503 setFieldLabel : function(v)
9510 var ar = this.el.select('label > span',true);
9512 if (ar.elements.length) {
9513 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9514 this.fieldLabel = v;
9518 var br = this.el.select('label',true);
9520 if(br.elements.length) {
9521 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9522 this.fieldLabel = v;
9526 Roo.log('Cannot Found any of label > span || label in input');
9530 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9531 this.fieldLabel = v;
9546 * @class Roo.bootstrap.TextArea
9547 * @extends Roo.bootstrap.Input
9548 * Bootstrap TextArea class
9549 * @cfg {Number} cols Specifies the visible width of a text area
9550 * @cfg {Number} rows Specifies the visible number of lines in a text area
9551 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9552 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9553 * @cfg {string} html text
9556 * Create a new TextArea
9557 * @param {Object} config The config object
9560 Roo.bootstrap.TextArea = function(config){
9561 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9565 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9575 getAutoCreate : function(){
9577 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9583 if(this.inputType != 'hidden'){
9584 cfg.cls = 'form-group' //input-group
9592 value : this.value || '',
9593 html: this.html || '',
9594 cls : 'form-control',
9595 placeholder : this.placeholder || ''
9599 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9600 input.maxLength = this.maxLength;
9604 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9608 input.cols = this.cols;
9611 if (this.readOnly) {
9612 input.readonly = true;
9616 input.name = this.name;
9620 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9624 ['xs','sm','md','lg'].map(function(size){
9625 if (settings[size]) {
9626 cfg.cls += ' col-' + size + '-' + settings[size];
9630 var inputblock = input;
9632 if(this.hasFeedback && !this.allowBlank){
9636 cls: 'glyphicon form-control-feedback'
9640 cls : 'has-feedback',
9649 if (this.before || this.after) {
9652 cls : 'input-group',
9656 inputblock.cn.push({
9658 cls : 'input-group-addon',
9663 inputblock.cn.push(input);
9665 if(this.hasFeedback && !this.allowBlank){
9666 inputblock.cls += ' has-feedback';
9667 inputblock.cn.push(feedback);
9671 inputblock.cn.push({
9673 cls : 'input-group-addon',
9680 if (align ==='left' && this.fieldLabel.length) {
9685 cls : 'control-label',
9686 html : this.fieldLabel
9697 if(this.labelWidth > 12){
9698 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9701 if(this.labelWidth < 13 && this.labelmd == 0){
9702 this.labelmd = this.labelWidth;
9705 if(this.labellg > 0){
9706 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9707 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9710 if(this.labelmd > 0){
9711 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9712 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9715 if(this.labelsm > 0){
9716 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9717 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9720 if(this.labelxs > 0){
9721 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9722 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9725 } else if ( this.fieldLabel.length) {
9730 //cls : 'input-group-addon',
9731 html : this.fieldLabel
9749 if (this.disabled) {
9750 input.disabled=true;
9757 * return the real textarea element.
9759 inputEl: function ()
9761 return this.el.select('textarea.form-control',true).first();
9765 * Clear any invalid styles/messages for this field
9767 clearInvalid : function()
9770 if(!this.el || this.preventMark){ // not rendered
9774 var label = this.el.select('label', true).first();
9775 var icon = this.el.select('i.fa-star', true).first();
9781 this.el.removeClass(this.invalidClass);
9783 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9785 var feedback = this.el.select('.form-control-feedback', true).first();
9788 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9793 this.fireEvent('valid', this);
9797 * Mark this field as valid
9799 markValid : function()
9801 if(!this.el || this.preventMark){ // not rendered
9805 this.el.removeClass([this.invalidClass, this.validClass]);
9807 var feedback = this.el.select('.form-control-feedback', true).first();
9810 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9813 if(this.disabled || this.allowBlank){
9817 var label = this.el.select('label', true).first();
9818 var icon = this.el.select('i.fa-star', true).first();
9824 this.el.addClass(this.validClass);
9826 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9828 var feedback = this.el.select('.form-control-feedback', true).first();
9831 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9832 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9837 this.fireEvent('valid', this);
9841 * Mark this field as invalid
9842 * @param {String} msg The validation message
9844 markInvalid : function(msg)
9846 if(!this.el || this.preventMark){ // not rendered
9850 this.el.removeClass([this.invalidClass, this.validClass]);
9852 var feedback = this.el.select('.form-control-feedback', true).first();
9855 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9858 if(this.disabled || this.allowBlank){
9862 var label = this.el.select('label', true).first();
9863 var icon = this.el.select('i.fa-star', true).first();
9865 if(!this.getValue().length && label && !icon){
9866 this.el.createChild({
9868 cls : 'text-danger fa fa-lg fa-star',
9869 tooltip : 'This field is required',
9870 style : 'margin-right:5px;'
9874 this.el.addClass(this.invalidClass);
9876 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9878 var feedback = this.el.select('.form-control-feedback', true).first();
9881 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9883 if(this.getValue().length || this.forceFeedback){
9884 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9891 this.fireEvent('invalid', this, msg);
9899 * trigger field - base class for combo..
9904 * @class Roo.bootstrap.TriggerField
9905 * @extends Roo.bootstrap.Input
9906 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9907 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9908 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9909 * for which you can provide a custom implementation. For example:
9911 var trigger = new Roo.bootstrap.TriggerField();
9912 trigger.onTriggerClick = myTriggerFn;
9913 trigger.applyTo('my-field');
9916 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9917 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9918 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9919 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9920 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9923 * Create a new TriggerField.
9924 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9925 * to the base TextField)
9927 Roo.bootstrap.TriggerField = function(config){
9928 this.mimicing = false;
9929 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9932 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9934 * @cfg {String} triggerClass A CSS class to apply to the trigger
9937 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9942 * @cfg {Boolean} removable (true|false) special filter default false
9946 /** @cfg {Boolean} grow @hide */
9947 /** @cfg {Number} growMin @hide */
9948 /** @cfg {Number} growMax @hide */
9954 autoSize: Roo.emptyFn,
9961 actionMode : 'wrap',
9966 getAutoCreate : function(){
9968 var align = this.labelAlign || this.parentLabelAlign();
9973 cls: 'form-group' //input-group
9980 type : this.inputType,
9981 cls : 'form-control',
9982 autocomplete: 'new-password',
9983 placeholder : this.placeholder || ''
9987 input.name = this.name;
9990 input.cls += ' input-' + this.size;
9993 if (this.disabled) {
9994 input.disabled=true;
9997 var inputblock = input;
9999 if(this.hasFeedback && !this.allowBlank){
10003 cls: 'glyphicon form-control-feedback'
10006 if(this.removable && !this.editable && !this.tickable){
10008 cls : 'has-feedback',
10014 cls : 'roo-combo-removable-btn close'
10021 cls : 'has-feedback',
10030 if(this.removable && !this.editable && !this.tickable){
10032 cls : 'roo-removable',
10038 cls : 'roo-combo-removable-btn close'
10045 if (this.before || this.after) {
10048 cls : 'input-group',
10052 inputblock.cn.push({
10054 cls : 'input-group-addon',
10059 inputblock.cn.push(input);
10061 if(this.hasFeedback && !this.allowBlank){
10062 inputblock.cls += ' has-feedback';
10063 inputblock.cn.push(feedback);
10067 inputblock.cn.push({
10069 cls : 'input-group-addon',
10082 cls: 'form-hidden-field'
10096 cls: 'form-hidden-field'
10100 cls: 'roo-select2-choices',
10104 cls: 'roo-select2-search-field',
10117 cls: 'roo-select2-container input-group',
10122 // cls: 'typeahead typeahead-long dropdown-menu',
10123 // style: 'display:none'
10128 if(!this.multiple && this.showToggleBtn){
10134 if (this.caret != false) {
10137 cls: 'fa fa-' + this.caret
10144 cls : 'input-group-addon btn dropdown-toggle',
10149 cls: 'combobox-clear',
10163 combobox.cls += ' roo-select2-container-multi';
10166 if (align ==='left' && this.fieldLabel.length) {
10168 cfg.cls += ' roo-form-group-label-left';
10173 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10174 tooltip : 'This field is required'
10179 cls : 'control-label',
10180 html : this.fieldLabel
10192 var labelCfg = cfg.cn[1];
10193 var contentCfg = cfg.cn[2];
10195 if(this.indicatorpos == 'right'){
10200 cls : 'control-label',
10204 html : this.fieldLabel
10208 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10209 tooltip : 'This field is required'
10222 labelCfg = cfg.cn[0];
10223 contentCfg = cfg.cn[1];
10226 if(this.labelWidth > 12){
10227 labelCfg.style = "width: " + this.labelWidth + 'px';
10230 if(this.labelWidth < 13 && this.labelmd == 0){
10231 this.labelmd = this.labelWidth;
10234 if(this.labellg > 0){
10235 labelCfg.cls += ' col-lg-' + this.labellg;
10236 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10239 if(this.labelmd > 0){
10240 labelCfg.cls += ' col-md-' + this.labelmd;
10241 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10244 if(this.labelsm > 0){
10245 labelCfg.cls += ' col-sm-' + this.labelsm;
10246 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10249 if(this.labelxs > 0){
10250 labelCfg.cls += ' col-xs-' + this.labelxs;
10251 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10254 } else if ( this.fieldLabel.length) {
10255 // Roo.log(" label");
10259 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10260 tooltip : 'This field is required'
10264 //cls : 'input-group-addon',
10265 html : this.fieldLabel
10273 if(this.indicatorpos == 'right'){
10281 html : this.fieldLabel
10285 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10286 tooltip : 'This field is required'
10299 // Roo.log(" no label && no align");
10306 ['xs','sm','md','lg'].map(function(size){
10307 if (settings[size]) {
10308 cfg.cls += ' col-' + size + '-' + settings[size];
10319 onResize : function(w, h){
10320 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10321 // if(typeof w == 'number'){
10322 // var x = w - this.trigger.getWidth();
10323 // this.inputEl().setWidth(this.adjustWidth('input', x));
10324 // this.trigger.setStyle('left', x+'px');
10329 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10332 getResizeEl : function(){
10333 return this.inputEl();
10337 getPositionEl : function(){
10338 return this.inputEl();
10342 alignErrorIcon : function(){
10343 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10347 initEvents : function(){
10351 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10352 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10353 if(!this.multiple && this.showToggleBtn){
10354 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10355 if(this.hideTrigger){
10356 this.trigger.setDisplayed(false);
10358 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10362 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10365 if(this.removable && !this.editable && !this.tickable){
10366 var close = this.closeTriggerEl();
10369 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10370 close.on('click', this.removeBtnClick, this, close);
10374 //this.trigger.addClassOnOver('x-form-trigger-over');
10375 //this.trigger.addClassOnClick('x-form-trigger-click');
10378 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10382 closeTriggerEl : function()
10384 var close = this.el.select('.roo-combo-removable-btn', true).first();
10385 return close ? close : false;
10388 removeBtnClick : function(e, h, el)
10390 e.preventDefault();
10392 if(this.fireEvent("remove", this) !== false){
10394 this.fireEvent("afterremove", this)
10398 createList : function()
10400 this.list = Roo.get(document.body).createChild({
10402 cls: 'typeahead typeahead-long dropdown-menu',
10403 style: 'display:none'
10406 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10411 initTrigger : function(){
10416 onDestroy : function(){
10418 this.trigger.removeAllListeners();
10419 // this.trigger.remove();
10422 // this.wrap.remove();
10424 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10428 onFocus : function(){
10429 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10431 if(!this.mimicing){
10432 this.wrap.addClass('x-trigger-wrap-focus');
10433 this.mimicing = true;
10434 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10435 if(this.monitorTab){
10436 this.el.on("keydown", this.checkTab, this);
10443 checkTab : function(e){
10444 if(e.getKey() == e.TAB){
10445 this.triggerBlur();
10450 onBlur : function(){
10455 mimicBlur : function(e, t){
10457 if(!this.wrap.contains(t) && this.validateBlur()){
10458 this.triggerBlur();
10464 triggerBlur : function(){
10465 this.mimicing = false;
10466 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10467 if(this.monitorTab){
10468 this.el.un("keydown", this.checkTab, this);
10470 //this.wrap.removeClass('x-trigger-wrap-focus');
10471 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10475 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10476 validateBlur : function(e, t){
10481 onDisable : function(){
10482 this.inputEl().dom.disabled = true;
10483 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10485 // this.wrap.addClass('x-item-disabled');
10490 onEnable : function(){
10491 this.inputEl().dom.disabled = false;
10492 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10494 // this.el.removeClass('x-item-disabled');
10499 onShow : function(){
10500 var ae = this.getActionEl();
10503 ae.dom.style.display = '';
10504 ae.dom.style.visibility = 'visible';
10510 onHide : function(){
10511 var ae = this.getActionEl();
10512 ae.dom.style.display = 'none';
10516 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10517 * by an implementing function.
10519 * @param {EventObject} e
10521 onTriggerClick : Roo.emptyFn
10525 * Ext JS Library 1.1.1
10526 * Copyright(c) 2006-2007, Ext JS, LLC.
10528 * Originally Released Under LGPL - original licence link has changed is not relivant.
10531 * <script type="text/javascript">
10536 * @class Roo.data.SortTypes
10538 * Defines the default sorting (casting?) comparison functions used when sorting data.
10540 Roo.data.SortTypes = {
10542 * Default sort that does nothing
10543 * @param {Mixed} s The value being converted
10544 * @return {Mixed} The comparison value
10546 none : function(s){
10551 * The regular expression used to strip tags
10555 stripTagsRE : /<\/?[^>]+>/gi,
10558 * Strips all HTML tags to sort on text only
10559 * @param {Mixed} s The value being converted
10560 * @return {String} The comparison value
10562 asText : function(s){
10563 return String(s).replace(this.stripTagsRE, "");
10567 * Strips all HTML tags to sort on text only - Case insensitive
10568 * @param {Mixed} s The value being converted
10569 * @return {String} The comparison value
10571 asUCText : function(s){
10572 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10576 * Case insensitive string
10577 * @param {Mixed} s The value being converted
10578 * @return {String} The comparison value
10580 asUCString : function(s) {
10581 return String(s).toUpperCase();
10586 * @param {Mixed} s The value being converted
10587 * @return {Number} The comparison value
10589 asDate : function(s) {
10593 if(s instanceof Date){
10594 return s.getTime();
10596 return Date.parse(String(s));
10601 * @param {Mixed} s The value being converted
10602 * @return {Float} The comparison value
10604 asFloat : function(s) {
10605 var val = parseFloat(String(s).replace(/,/g, ""));
10614 * @param {Mixed} s The value being converted
10615 * @return {Number} The comparison value
10617 asInt : function(s) {
10618 var val = parseInt(String(s).replace(/,/g, ""));
10626 * Ext JS Library 1.1.1
10627 * Copyright(c) 2006-2007, Ext JS, LLC.
10629 * Originally Released Under LGPL - original licence link has changed is not relivant.
10632 * <script type="text/javascript">
10636 * @class Roo.data.Record
10637 * Instances of this class encapsulate both record <em>definition</em> information, and record
10638 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10639 * to access Records cached in an {@link Roo.data.Store} object.<br>
10641 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10642 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10645 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10647 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10648 * {@link #create}. The parameters are the same.
10649 * @param {Array} data An associative Array of data values keyed by the field name.
10650 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10651 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10652 * not specified an integer id is generated.
10654 Roo.data.Record = function(data, id){
10655 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10660 * Generate a constructor for a specific record layout.
10661 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10662 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10663 * Each field definition object may contain the following properties: <ul>
10664 * <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,
10665 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10666 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10667 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10668 * is being used, then this is a string containing the javascript expression to reference the data relative to
10669 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10670 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10671 * this may be omitted.</p></li>
10672 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10673 * <ul><li>auto (Default, implies no conversion)</li>
10678 * <li>date</li></ul></p></li>
10679 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10680 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10681 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10682 * by the Reader into an object that will be stored in the Record. It is passed the
10683 * following parameters:<ul>
10684 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10686 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10688 * <br>usage:<br><pre><code>
10689 var TopicRecord = Roo.data.Record.create(
10690 {name: 'title', mapping: 'topic_title'},
10691 {name: 'author', mapping: 'username'},
10692 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10693 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10694 {name: 'lastPoster', mapping: 'user2'},
10695 {name: 'excerpt', mapping: 'post_text'}
10698 var myNewRecord = new TopicRecord({
10699 title: 'Do my job please',
10702 lastPost: new Date(),
10703 lastPoster: 'Animal',
10704 excerpt: 'No way dude!'
10706 myStore.add(myNewRecord);
10711 Roo.data.Record.create = function(o){
10712 var f = function(){
10713 f.superclass.constructor.apply(this, arguments);
10715 Roo.extend(f, Roo.data.Record);
10716 var p = f.prototype;
10717 p.fields = new Roo.util.MixedCollection(false, function(field){
10720 for(var i = 0, len = o.length; i < len; i++){
10721 p.fields.add(new Roo.data.Field(o[i]));
10723 f.getField = function(name){
10724 return p.fields.get(name);
10729 Roo.data.Record.AUTO_ID = 1000;
10730 Roo.data.Record.EDIT = 'edit';
10731 Roo.data.Record.REJECT = 'reject';
10732 Roo.data.Record.COMMIT = 'commit';
10734 Roo.data.Record.prototype = {
10736 * Readonly flag - true if this record has been modified.
10745 join : function(store){
10746 this.store = store;
10750 * Set the named field to the specified value.
10751 * @param {String} name The name of the field to set.
10752 * @param {Object} value The value to set the field to.
10754 set : function(name, value){
10755 if(this.data[name] == value){
10759 if(!this.modified){
10760 this.modified = {};
10762 if(typeof this.modified[name] == 'undefined'){
10763 this.modified[name] = this.data[name];
10765 this.data[name] = value;
10766 if(!this.editing && this.store){
10767 this.store.afterEdit(this);
10772 * Get the value of the named field.
10773 * @param {String} name The name of the field to get the value of.
10774 * @return {Object} The value of the field.
10776 get : function(name){
10777 return this.data[name];
10781 beginEdit : function(){
10782 this.editing = true;
10783 this.modified = {};
10787 cancelEdit : function(){
10788 this.editing = false;
10789 delete this.modified;
10793 endEdit : function(){
10794 this.editing = false;
10795 if(this.dirty && this.store){
10796 this.store.afterEdit(this);
10801 * Usually called by the {@link Roo.data.Store} which owns the Record.
10802 * Rejects all changes made to the Record since either creation, or the last commit operation.
10803 * Modified fields are reverted to their original values.
10805 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10806 * of reject operations.
10808 reject : function(){
10809 var m = this.modified;
10811 if(typeof m[n] != "function"){
10812 this.data[n] = m[n];
10815 this.dirty = false;
10816 delete this.modified;
10817 this.editing = false;
10819 this.store.afterReject(this);
10824 * Usually called by the {@link Roo.data.Store} which owns the Record.
10825 * Commits all changes made to the Record since either creation, or the last commit operation.
10827 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10828 * of commit operations.
10830 commit : function(){
10831 this.dirty = false;
10832 delete this.modified;
10833 this.editing = false;
10835 this.store.afterCommit(this);
10840 hasError : function(){
10841 return this.error != null;
10845 clearError : function(){
10850 * Creates a copy of this record.
10851 * @param {String} id (optional) A new record id if you don't want to use this record's id
10854 copy : function(newId) {
10855 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10859 * Ext JS Library 1.1.1
10860 * Copyright(c) 2006-2007, Ext JS, LLC.
10862 * Originally Released Under LGPL - original licence link has changed is not relivant.
10865 * <script type="text/javascript">
10871 * @class Roo.data.Store
10872 * @extends Roo.util.Observable
10873 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10874 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10876 * 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
10877 * has no knowledge of the format of the data returned by the Proxy.<br>
10879 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10880 * instances from the data object. These records are cached and made available through accessor functions.
10882 * Creates a new Store.
10883 * @param {Object} config A config object containing the objects needed for the Store to access data,
10884 * and read the data into Records.
10886 Roo.data.Store = function(config){
10887 this.data = new Roo.util.MixedCollection(false);
10888 this.data.getKey = function(o){
10891 this.baseParams = {};
10893 this.paramNames = {
10898 "multisort" : "_multisort"
10901 if(config && config.data){
10902 this.inlineData = config.data;
10903 delete config.data;
10906 Roo.apply(this, config);
10908 if(this.reader){ // reader passed
10909 this.reader = Roo.factory(this.reader, Roo.data);
10910 this.reader.xmodule = this.xmodule || false;
10911 if(!this.recordType){
10912 this.recordType = this.reader.recordType;
10914 if(this.reader.onMetaChange){
10915 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10919 if(this.recordType){
10920 this.fields = this.recordType.prototype.fields;
10922 this.modified = [];
10926 * @event datachanged
10927 * Fires when the data cache has changed, and a widget which is using this Store
10928 * as a Record cache should refresh its view.
10929 * @param {Store} this
10931 datachanged : true,
10933 * @event metachange
10934 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10935 * @param {Store} this
10936 * @param {Object} meta The JSON metadata
10941 * Fires when Records have been added to the Store
10942 * @param {Store} this
10943 * @param {Roo.data.Record[]} records The array of Records added
10944 * @param {Number} index The index at which the record(s) were added
10949 * Fires when a Record has been removed from the Store
10950 * @param {Store} this
10951 * @param {Roo.data.Record} record The Record that was removed
10952 * @param {Number} index The index at which the record was removed
10957 * Fires when a Record has been updated
10958 * @param {Store} this
10959 * @param {Roo.data.Record} record The Record that was updated
10960 * @param {String} operation The update operation being performed. Value may be one of:
10962 Roo.data.Record.EDIT
10963 Roo.data.Record.REJECT
10964 Roo.data.Record.COMMIT
10970 * Fires when the data cache has been cleared.
10971 * @param {Store} this
10975 * @event beforeload
10976 * Fires before a request is made for a new data object. If the beforeload handler returns false
10977 * the load action will be canceled.
10978 * @param {Store} this
10979 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10983 * @event beforeloadadd
10984 * Fires after a new set of Records has been loaded.
10985 * @param {Store} this
10986 * @param {Roo.data.Record[]} records The Records that were loaded
10987 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10989 beforeloadadd : true,
10992 * Fires after a new set of Records has been loaded, before they are added to the store.
10993 * @param {Store} this
10994 * @param {Roo.data.Record[]} records The Records that were loaded
10995 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10996 * @params {Object} return from reader
11000 * @event loadexception
11001 * Fires if an exception occurs in the Proxy during loading.
11002 * Called with the signature of the Proxy's "loadexception" event.
11003 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11006 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11007 * @param {Object} load options
11008 * @param {Object} jsonData from your request (normally this contains the Exception)
11010 loadexception : true
11014 this.proxy = Roo.factory(this.proxy, Roo.data);
11015 this.proxy.xmodule = this.xmodule || false;
11016 this.relayEvents(this.proxy, ["loadexception"]);
11018 this.sortToggle = {};
11019 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11021 Roo.data.Store.superclass.constructor.call(this);
11023 if(this.inlineData){
11024 this.loadData(this.inlineData);
11025 delete this.inlineData;
11029 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11031 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11032 * without a remote query - used by combo/forms at present.
11036 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11039 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11042 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11043 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11046 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11047 * on any HTTP request
11050 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11053 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11057 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11058 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11060 remoteSort : false,
11063 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11064 * loaded or when a record is removed. (defaults to false).
11066 pruneModifiedRecords : false,
11069 lastOptions : null,
11072 * Add Records to the Store and fires the add event.
11073 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11075 add : function(records){
11076 records = [].concat(records);
11077 for(var i = 0, len = records.length; i < len; i++){
11078 records[i].join(this);
11080 var index = this.data.length;
11081 this.data.addAll(records);
11082 this.fireEvent("add", this, records, index);
11086 * Remove a Record from the Store and fires the remove event.
11087 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11089 remove : function(record){
11090 var index = this.data.indexOf(record);
11091 this.data.removeAt(index);
11092 if(this.pruneModifiedRecords){
11093 this.modified.remove(record);
11095 this.fireEvent("remove", this, record, index);
11099 * Remove all Records from the Store and fires the clear event.
11101 removeAll : function(){
11103 if(this.pruneModifiedRecords){
11104 this.modified = [];
11106 this.fireEvent("clear", this);
11110 * Inserts Records to the Store at the given index and fires the add event.
11111 * @param {Number} index The start index at which to insert the passed Records.
11112 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11114 insert : function(index, records){
11115 records = [].concat(records);
11116 for(var i = 0, len = records.length; i < len; i++){
11117 this.data.insert(index, records[i]);
11118 records[i].join(this);
11120 this.fireEvent("add", this, records, index);
11124 * Get the index within the cache of the passed Record.
11125 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11126 * @return {Number} The index of the passed Record. Returns -1 if not found.
11128 indexOf : function(record){
11129 return this.data.indexOf(record);
11133 * Get the index within the cache of the Record with the passed id.
11134 * @param {String} id The id of the Record to find.
11135 * @return {Number} The index of the Record. Returns -1 if not found.
11137 indexOfId : function(id){
11138 return this.data.indexOfKey(id);
11142 * Get the Record with the specified id.
11143 * @param {String} id The id of the Record to find.
11144 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11146 getById : function(id){
11147 return this.data.key(id);
11151 * Get the Record at the specified index.
11152 * @param {Number} index The index of the Record to find.
11153 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11155 getAt : function(index){
11156 return this.data.itemAt(index);
11160 * Returns a range of Records between specified indices.
11161 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11162 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11163 * @return {Roo.data.Record[]} An array of Records
11165 getRange : function(start, end){
11166 return this.data.getRange(start, end);
11170 storeOptions : function(o){
11171 o = Roo.apply({}, o);
11174 this.lastOptions = o;
11178 * Loads the Record cache from the configured Proxy using the configured Reader.
11180 * If using remote paging, then the first load call must specify the <em>start</em>
11181 * and <em>limit</em> properties in the options.params property to establish the initial
11182 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11184 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11185 * and this call will return before the new data has been loaded. Perform any post-processing
11186 * in a callback function, or in a "load" event handler.</strong>
11188 * @param {Object} options An object containing properties which control loading options:<ul>
11189 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11190 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11191 * passed the following arguments:<ul>
11192 * <li>r : Roo.data.Record[]</li>
11193 * <li>options: Options object from the load call</li>
11194 * <li>success: Boolean success indicator</li></ul></li>
11195 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11196 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11199 load : function(options){
11200 options = options || {};
11201 if(this.fireEvent("beforeload", this, options) !== false){
11202 this.storeOptions(options);
11203 var p = Roo.apply(options.params || {}, this.baseParams);
11204 // if meta was not loaded from remote source.. try requesting it.
11205 if (!this.reader.metaFromRemote) {
11206 p._requestMeta = 1;
11208 if(this.sortInfo && this.remoteSort){
11209 var pn = this.paramNames;
11210 p[pn["sort"]] = this.sortInfo.field;
11211 p[pn["dir"]] = this.sortInfo.direction;
11213 if (this.multiSort) {
11214 var pn = this.paramNames;
11215 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11218 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11223 * Reloads the Record cache from the configured Proxy using the configured Reader and
11224 * the options from the last load operation performed.
11225 * @param {Object} options (optional) An object containing properties which may override the options
11226 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11227 * the most recently used options are reused).
11229 reload : function(options){
11230 this.load(Roo.applyIf(options||{}, this.lastOptions));
11234 // Called as a callback by the Reader during a load operation.
11235 loadRecords : function(o, options, success){
11236 if(!o || success === false){
11237 if(success !== false){
11238 this.fireEvent("load", this, [], options, o);
11240 if(options.callback){
11241 options.callback.call(options.scope || this, [], options, false);
11245 // if data returned failure - throw an exception.
11246 if (o.success === false) {
11247 // show a message if no listener is registered.
11248 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11249 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11251 // loadmask wil be hooked into this..
11252 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11255 var r = o.records, t = o.totalRecords || r.length;
11257 this.fireEvent("beforeloadadd", this, r, options, o);
11259 if(!options || options.add !== true){
11260 if(this.pruneModifiedRecords){
11261 this.modified = [];
11263 for(var i = 0, len = r.length; i < len; i++){
11267 this.data = this.snapshot;
11268 delete this.snapshot;
11271 this.data.addAll(r);
11272 this.totalLength = t;
11274 this.fireEvent("datachanged", this);
11276 this.totalLength = Math.max(t, this.data.length+r.length);
11280 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11282 var e = new Roo.data.Record({});
11284 e.set(this.parent.displayField, this.parent.emptyTitle);
11285 e.set(this.parent.valueField, '');
11290 this.fireEvent("load", this, r, options, o);
11291 if(options.callback){
11292 options.callback.call(options.scope || this, r, options, true);
11298 * Loads data from a passed data block. A Reader which understands the format of the data
11299 * must have been configured in the constructor.
11300 * @param {Object} data The data block from which to read the Records. The format of the data expected
11301 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11302 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11304 loadData : function(o, append){
11305 var r = this.reader.readRecords(o);
11306 this.loadRecords(r, {add: append}, true);
11310 * Gets the number of cached records.
11312 * <em>If using paging, this may not be the total size of the dataset. If the data object
11313 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11314 * the data set size</em>
11316 getCount : function(){
11317 return this.data.length || 0;
11321 * Gets the total number of records in the dataset as returned by the server.
11323 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11324 * the dataset size</em>
11326 getTotalCount : function(){
11327 return this.totalLength || 0;
11331 * Returns the sort state of the Store as an object with two properties:
11333 field {String} The name of the field by which the Records are sorted
11334 direction {String} The sort order, "ASC" or "DESC"
11337 getSortState : function(){
11338 return this.sortInfo;
11342 applySort : function(){
11343 if(this.sortInfo && !this.remoteSort){
11344 var s = this.sortInfo, f = s.field;
11345 var st = this.fields.get(f).sortType;
11346 var fn = function(r1, r2){
11347 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11348 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11350 this.data.sort(s.direction, fn);
11351 if(this.snapshot && this.snapshot != this.data){
11352 this.snapshot.sort(s.direction, fn);
11358 * Sets the default sort column and order to be used by the next load operation.
11359 * @param {String} fieldName The name of the field to sort by.
11360 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11362 setDefaultSort : function(field, dir){
11363 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11367 * Sort the Records.
11368 * If remote sorting is used, the sort is performed on the server, and the cache is
11369 * reloaded. If local sorting is used, the cache is sorted internally.
11370 * @param {String} fieldName The name of the field to sort by.
11371 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11373 sort : function(fieldName, dir){
11374 var f = this.fields.get(fieldName);
11376 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11378 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11379 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11384 this.sortToggle[f.name] = dir;
11385 this.sortInfo = {field: f.name, direction: dir};
11386 if(!this.remoteSort){
11388 this.fireEvent("datachanged", this);
11390 this.load(this.lastOptions);
11395 * Calls the specified function for each of the Records in the cache.
11396 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11397 * Returning <em>false</em> aborts and exits the iteration.
11398 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11400 each : function(fn, scope){
11401 this.data.each(fn, scope);
11405 * Gets all records modified since the last commit. Modified records are persisted across load operations
11406 * (e.g., during paging).
11407 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11409 getModifiedRecords : function(){
11410 return this.modified;
11414 createFilterFn : function(property, value, anyMatch){
11415 if(!value.exec){ // not a regex
11416 value = String(value);
11417 if(value.length == 0){
11420 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11422 return function(r){
11423 return value.test(r.data[property]);
11428 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11429 * @param {String} property A field on your records
11430 * @param {Number} start The record index to start at (defaults to 0)
11431 * @param {Number} end The last record index to include (defaults to length - 1)
11432 * @return {Number} The sum
11434 sum : function(property, start, end){
11435 var rs = this.data.items, v = 0;
11436 start = start || 0;
11437 end = (end || end === 0) ? end : rs.length-1;
11439 for(var i = start; i <= end; i++){
11440 v += (rs[i].data[property] || 0);
11446 * Filter the records by a specified property.
11447 * @param {String} field A field on your records
11448 * @param {String/RegExp} value Either a string that the field
11449 * should start with or a RegExp to test against the field
11450 * @param {Boolean} anyMatch True to match any part not just the beginning
11452 filter : function(property, value, anyMatch){
11453 var fn = this.createFilterFn(property, value, anyMatch);
11454 return fn ? this.filterBy(fn) : this.clearFilter();
11458 * Filter by a function. The specified function will be called with each
11459 * record in this data source. If the function returns true the record is included,
11460 * otherwise it is filtered.
11461 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11462 * @param {Object} scope (optional) The scope of the function (defaults to this)
11464 filterBy : function(fn, scope){
11465 this.snapshot = this.snapshot || this.data;
11466 this.data = this.queryBy(fn, scope||this);
11467 this.fireEvent("datachanged", this);
11471 * Query the records by a specified property.
11472 * @param {String} field A field on your records
11473 * @param {String/RegExp} value Either a string that the field
11474 * should start with or a RegExp to test against the field
11475 * @param {Boolean} anyMatch True to match any part not just the beginning
11476 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11478 query : function(property, value, anyMatch){
11479 var fn = this.createFilterFn(property, value, anyMatch);
11480 return fn ? this.queryBy(fn) : this.data.clone();
11484 * Query by a function. The specified function will be called with each
11485 * record in this data source. If the function returns true the record is included
11487 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11488 * @param {Object} scope (optional) The scope of the function (defaults to this)
11489 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11491 queryBy : function(fn, scope){
11492 var data = this.snapshot || this.data;
11493 return data.filterBy(fn, scope||this);
11497 * Collects unique values for a particular dataIndex from this store.
11498 * @param {String} dataIndex The property to collect
11499 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11500 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11501 * @return {Array} An array of the unique values
11503 collect : function(dataIndex, allowNull, bypassFilter){
11504 var d = (bypassFilter === true && this.snapshot) ?
11505 this.snapshot.items : this.data.items;
11506 var v, sv, r = [], l = {};
11507 for(var i = 0, len = d.length; i < len; i++){
11508 v = d[i].data[dataIndex];
11510 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11519 * Revert to a view of the Record cache with no filtering applied.
11520 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11522 clearFilter : function(suppressEvent){
11523 if(this.snapshot && this.snapshot != this.data){
11524 this.data = this.snapshot;
11525 delete this.snapshot;
11526 if(suppressEvent !== true){
11527 this.fireEvent("datachanged", this);
11533 afterEdit : function(record){
11534 if(this.modified.indexOf(record) == -1){
11535 this.modified.push(record);
11537 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11541 afterReject : function(record){
11542 this.modified.remove(record);
11543 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11547 afterCommit : function(record){
11548 this.modified.remove(record);
11549 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11553 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11554 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11556 commitChanges : function(){
11557 var m = this.modified.slice(0);
11558 this.modified = [];
11559 for(var i = 0, len = m.length; i < len; i++){
11565 * Cancel outstanding changes on all changed records.
11567 rejectChanges : function(){
11568 var m = this.modified.slice(0);
11569 this.modified = [];
11570 for(var i = 0, len = m.length; i < len; i++){
11575 onMetaChange : function(meta, rtype, o){
11576 this.recordType = rtype;
11577 this.fields = rtype.prototype.fields;
11578 delete this.snapshot;
11579 this.sortInfo = meta.sortInfo || this.sortInfo;
11580 this.modified = [];
11581 this.fireEvent('metachange', this, this.reader.meta);
11584 moveIndex : function(data, type)
11586 var index = this.indexOf(data);
11588 var newIndex = index + type;
11592 this.insert(newIndex, data);
11597 * Ext JS Library 1.1.1
11598 * Copyright(c) 2006-2007, Ext JS, LLC.
11600 * Originally Released Under LGPL - original licence link has changed is not relivant.
11603 * <script type="text/javascript">
11607 * @class Roo.data.SimpleStore
11608 * @extends Roo.data.Store
11609 * Small helper class to make creating Stores from Array data easier.
11610 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11611 * @cfg {Array} fields An array of field definition objects, or field name strings.
11612 * @cfg {Array} data The multi-dimensional array of data
11614 * @param {Object} config
11616 Roo.data.SimpleStore = function(config){
11617 Roo.data.SimpleStore.superclass.constructor.call(this, {
11619 reader: new Roo.data.ArrayReader({
11622 Roo.data.Record.create(config.fields)
11624 proxy : new Roo.data.MemoryProxy(config.data)
11628 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11630 * Ext JS Library 1.1.1
11631 * Copyright(c) 2006-2007, Ext JS, LLC.
11633 * Originally Released Under LGPL - original licence link has changed is not relivant.
11636 * <script type="text/javascript">
11641 * @extends Roo.data.Store
11642 * @class Roo.data.JsonStore
11643 * Small helper class to make creating Stores for JSON data easier. <br/>
11645 var store = new Roo.data.JsonStore({
11646 url: 'get-images.php',
11648 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11651 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11652 * JsonReader and HttpProxy (unless inline data is provided).</b>
11653 * @cfg {Array} fields An array of field definition objects, or field name strings.
11655 * @param {Object} config
11657 Roo.data.JsonStore = function(c){
11658 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11659 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11660 reader: new Roo.data.JsonReader(c, c.fields)
11663 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11665 * Ext JS Library 1.1.1
11666 * Copyright(c) 2006-2007, Ext JS, LLC.
11668 * Originally Released Under LGPL - original licence link has changed is not relivant.
11671 * <script type="text/javascript">
11675 Roo.data.Field = function(config){
11676 if(typeof config == "string"){
11677 config = {name: config};
11679 Roo.apply(this, config);
11682 this.type = "auto";
11685 var st = Roo.data.SortTypes;
11686 // named sortTypes are supported, here we look them up
11687 if(typeof this.sortType == "string"){
11688 this.sortType = st[this.sortType];
11691 // set default sortType for strings and dates
11692 if(!this.sortType){
11695 this.sortType = st.asUCString;
11698 this.sortType = st.asDate;
11701 this.sortType = st.none;
11706 var stripRe = /[\$,%]/g;
11708 // prebuilt conversion function for this field, instead of
11709 // switching every time we're reading a value
11711 var cv, dateFormat = this.dateFormat;
11716 cv = function(v){ return v; };
11719 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11723 return v !== undefined && v !== null && v !== '' ?
11724 parseInt(String(v).replace(stripRe, ""), 10) : '';
11729 return v !== undefined && v !== null && v !== '' ?
11730 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11735 cv = function(v){ return v === true || v === "true" || v == 1; };
11742 if(v instanceof Date){
11746 if(dateFormat == "timestamp"){
11747 return new Date(v*1000);
11749 return Date.parseDate(v, dateFormat);
11751 var parsed = Date.parse(v);
11752 return parsed ? new Date(parsed) : null;
11761 Roo.data.Field.prototype = {
11769 * Ext JS Library 1.1.1
11770 * Copyright(c) 2006-2007, Ext JS, LLC.
11772 * Originally Released Under LGPL - original licence link has changed is not relivant.
11775 * <script type="text/javascript">
11778 // Base class for reading structured data from a data source. This class is intended to be
11779 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11782 * @class Roo.data.DataReader
11783 * Base class for reading structured data from a data source. This class is intended to be
11784 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11787 Roo.data.DataReader = function(meta, recordType){
11791 this.recordType = recordType instanceof Array ?
11792 Roo.data.Record.create(recordType) : recordType;
11795 Roo.data.DataReader.prototype = {
11797 * Create an empty record
11798 * @param {Object} data (optional) - overlay some values
11799 * @return {Roo.data.Record} record created.
11801 newRow : function(d) {
11803 this.recordType.prototype.fields.each(function(c) {
11805 case 'int' : da[c.name] = 0; break;
11806 case 'date' : da[c.name] = new Date(); break;
11807 case 'float' : da[c.name] = 0.0; break;
11808 case 'boolean' : da[c.name] = false; break;
11809 default : da[c.name] = ""; break;
11813 return new this.recordType(Roo.apply(da, d));
11818 * Ext JS Library 1.1.1
11819 * Copyright(c) 2006-2007, Ext JS, LLC.
11821 * Originally Released Under LGPL - original licence link has changed is not relivant.
11824 * <script type="text/javascript">
11828 * @class Roo.data.DataProxy
11829 * @extends Roo.data.Observable
11830 * This class is an abstract base class for implementations which provide retrieval of
11831 * unformatted data objects.<br>
11833 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11834 * (of the appropriate type which knows how to parse the data object) to provide a block of
11835 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11837 * Custom implementations must implement the load method as described in
11838 * {@link Roo.data.HttpProxy#load}.
11840 Roo.data.DataProxy = function(){
11843 * @event beforeload
11844 * Fires before a network request is made to retrieve a data object.
11845 * @param {Object} This DataProxy object.
11846 * @param {Object} params The params parameter to the load function.
11851 * Fires before the load method's callback is called.
11852 * @param {Object} This DataProxy object.
11853 * @param {Object} o The data object.
11854 * @param {Object} arg The callback argument object passed to the load function.
11858 * @event loadexception
11859 * Fires if an Exception occurs during data retrieval.
11860 * @param {Object} This DataProxy object.
11861 * @param {Object} o The data object.
11862 * @param {Object} arg The callback argument object passed to the load function.
11863 * @param {Object} e The Exception.
11865 loadexception : true
11867 Roo.data.DataProxy.superclass.constructor.call(this);
11870 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11873 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11877 * Ext JS Library 1.1.1
11878 * Copyright(c) 2006-2007, Ext JS, LLC.
11880 * Originally Released Under LGPL - original licence link has changed is not relivant.
11883 * <script type="text/javascript">
11886 * @class Roo.data.MemoryProxy
11887 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11888 * to the Reader when its load method is called.
11890 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11892 Roo.data.MemoryProxy = function(data){
11896 Roo.data.MemoryProxy.superclass.constructor.call(this);
11900 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11903 * Load data from the requested source (in this case an in-memory
11904 * data object passed to the constructor), read the data object into
11905 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11906 * process that block using the passed callback.
11907 * @param {Object} params This parameter is not used by the MemoryProxy class.
11908 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11909 * object into a block of Roo.data.Records.
11910 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11911 * The function must be passed <ul>
11912 * <li>The Record block object</li>
11913 * <li>The "arg" argument from the load function</li>
11914 * <li>A boolean success indicator</li>
11916 * @param {Object} scope The scope in which to call the callback
11917 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11919 load : function(params, reader, callback, scope, arg){
11920 params = params || {};
11923 result = reader.readRecords(this.data);
11925 this.fireEvent("loadexception", this, arg, null, e);
11926 callback.call(scope, null, arg, false);
11929 callback.call(scope, result, arg, true);
11933 update : function(params, records){
11938 * Ext JS Library 1.1.1
11939 * Copyright(c) 2006-2007, Ext JS, LLC.
11941 * Originally Released Under LGPL - original licence link has changed is not relivant.
11944 * <script type="text/javascript">
11947 * @class Roo.data.HttpProxy
11948 * @extends Roo.data.DataProxy
11949 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11950 * configured to reference a certain URL.<br><br>
11952 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11953 * from which the running page was served.<br><br>
11955 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11957 * Be aware that to enable the browser to parse an XML document, the server must set
11958 * the Content-Type header in the HTTP response to "text/xml".
11960 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11961 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11962 * will be used to make the request.
11964 Roo.data.HttpProxy = function(conn){
11965 Roo.data.HttpProxy.superclass.constructor.call(this);
11966 // is conn a conn config or a real conn?
11968 this.useAjax = !conn || !conn.events;
11972 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11973 // thse are take from connection...
11976 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11979 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11980 * extra parameters to each request made by this object. (defaults to undefined)
11983 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11984 * to each request made by this object. (defaults to undefined)
11987 * @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)
11990 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11993 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11999 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12003 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12004 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12005 * a finer-grained basis than the DataProxy events.
12007 getConnection : function(){
12008 return this.useAjax ? Roo.Ajax : this.conn;
12012 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12013 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12014 * process that block using the passed callback.
12015 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12016 * for the request to the remote server.
12017 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12018 * object into a block of Roo.data.Records.
12019 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12020 * The function must be passed <ul>
12021 * <li>The Record block object</li>
12022 * <li>The "arg" argument from the load function</li>
12023 * <li>A boolean success indicator</li>
12025 * @param {Object} scope The scope in which to call the callback
12026 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12028 load : function(params, reader, callback, scope, arg){
12029 if(this.fireEvent("beforeload", this, params) !== false){
12031 params : params || {},
12033 callback : callback,
12038 callback : this.loadResponse,
12042 Roo.applyIf(o, this.conn);
12043 if(this.activeRequest){
12044 Roo.Ajax.abort(this.activeRequest);
12046 this.activeRequest = Roo.Ajax.request(o);
12048 this.conn.request(o);
12051 callback.call(scope||this, null, arg, false);
12056 loadResponse : function(o, success, response){
12057 delete this.activeRequest;
12059 this.fireEvent("loadexception", this, o, response);
12060 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12065 result = o.reader.read(response);
12067 this.fireEvent("loadexception", this, o, response, e);
12068 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12072 this.fireEvent("load", this, o, o.request.arg);
12073 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12077 update : function(dataSet){
12082 updateResponse : function(dataSet){
12087 * Ext JS Library 1.1.1
12088 * Copyright(c) 2006-2007, Ext JS, LLC.
12090 * Originally Released Under LGPL - original licence link has changed is not relivant.
12093 * <script type="text/javascript">
12097 * @class Roo.data.ScriptTagProxy
12098 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12099 * other than the originating domain of the running page.<br><br>
12101 * <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
12102 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12104 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12105 * source code that is used as the source inside a <script> tag.<br><br>
12107 * In order for the browser to process the returned data, the server must wrap the data object
12108 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12109 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12110 * depending on whether the callback name was passed:
12113 boolean scriptTag = false;
12114 String cb = request.getParameter("callback");
12117 response.setContentType("text/javascript");
12119 response.setContentType("application/x-json");
12121 Writer out = response.getWriter();
12123 out.write(cb + "(");
12125 out.print(dataBlock.toJsonString());
12132 * @param {Object} config A configuration object.
12134 Roo.data.ScriptTagProxy = function(config){
12135 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12136 Roo.apply(this, config);
12137 this.head = document.getElementsByTagName("head")[0];
12140 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12142 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12144 * @cfg {String} url The URL from which to request the data object.
12147 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12151 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12152 * the server the name of the callback function set up by the load call to process the returned data object.
12153 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12154 * javascript output which calls this named function passing the data object as its only parameter.
12156 callbackParam : "callback",
12158 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12159 * name to the request.
12164 * Load data from the configured URL, read the data object into
12165 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12166 * process that block using the passed callback.
12167 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12168 * for the request to the remote server.
12169 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12170 * object into a block of Roo.data.Records.
12171 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12172 * The function must be passed <ul>
12173 * <li>The Record block object</li>
12174 * <li>The "arg" argument from the load function</li>
12175 * <li>A boolean success indicator</li>
12177 * @param {Object} scope The scope in which to call the callback
12178 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12180 load : function(params, reader, callback, scope, arg){
12181 if(this.fireEvent("beforeload", this, params) !== false){
12183 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12185 var url = this.url;
12186 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12188 url += "&_dc=" + (new Date().getTime());
12190 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12193 cb : "stcCallback"+transId,
12194 scriptId : "stcScript"+transId,
12198 callback : callback,
12204 window[trans.cb] = function(o){
12205 conn.handleResponse(o, trans);
12208 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12210 if(this.autoAbort !== false){
12214 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12216 var script = document.createElement("script");
12217 script.setAttribute("src", url);
12218 script.setAttribute("type", "text/javascript");
12219 script.setAttribute("id", trans.scriptId);
12220 this.head.appendChild(script);
12222 this.trans = trans;
12224 callback.call(scope||this, null, arg, false);
12229 isLoading : function(){
12230 return this.trans ? true : false;
12234 * Abort the current server request.
12236 abort : function(){
12237 if(this.isLoading()){
12238 this.destroyTrans(this.trans);
12243 destroyTrans : function(trans, isLoaded){
12244 this.head.removeChild(document.getElementById(trans.scriptId));
12245 clearTimeout(trans.timeoutId);
12247 window[trans.cb] = undefined;
12249 delete window[trans.cb];
12252 // if hasn't been loaded, wait for load to remove it to prevent script error
12253 window[trans.cb] = function(){
12254 window[trans.cb] = undefined;
12256 delete window[trans.cb];
12263 handleResponse : function(o, trans){
12264 this.trans = false;
12265 this.destroyTrans(trans, true);
12268 result = trans.reader.readRecords(o);
12270 this.fireEvent("loadexception", this, o, trans.arg, e);
12271 trans.callback.call(trans.scope||window, null, trans.arg, false);
12274 this.fireEvent("load", this, o, trans.arg);
12275 trans.callback.call(trans.scope||window, result, trans.arg, true);
12279 handleFailure : function(trans){
12280 this.trans = false;
12281 this.destroyTrans(trans, false);
12282 this.fireEvent("loadexception", this, null, trans.arg);
12283 trans.callback.call(trans.scope||window, null, trans.arg, false);
12287 * Ext JS Library 1.1.1
12288 * Copyright(c) 2006-2007, Ext JS, LLC.
12290 * Originally Released Under LGPL - original licence link has changed is not relivant.
12293 * <script type="text/javascript">
12297 * @class Roo.data.JsonReader
12298 * @extends Roo.data.DataReader
12299 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12300 * based on mappings in a provided Roo.data.Record constructor.
12302 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12303 * in the reply previously.
12308 var RecordDef = Roo.data.Record.create([
12309 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12310 {name: 'occupation'} // This field will use "occupation" as the mapping.
12312 var myReader = new Roo.data.JsonReader({
12313 totalProperty: "results", // The property which contains the total dataset size (optional)
12314 root: "rows", // The property which contains an Array of row objects
12315 id: "id" // The property within each row object that provides an ID for the record (optional)
12319 * This would consume a JSON file like this:
12321 { 'results': 2, 'rows': [
12322 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12323 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12326 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12327 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12328 * paged from the remote server.
12329 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12330 * @cfg {String} root name of the property which contains the Array of row objects.
12331 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12332 * @cfg {Array} fields Array of field definition objects
12334 * Create a new JsonReader
12335 * @param {Object} meta Metadata configuration options
12336 * @param {Object} recordType Either an Array of field definition objects,
12337 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12339 Roo.data.JsonReader = function(meta, recordType){
12342 // set some defaults:
12343 Roo.applyIf(meta, {
12344 totalProperty: 'total',
12345 successProperty : 'success',
12350 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12352 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12355 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12356 * Used by Store query builder to append _requestMeta to params.
12359 metaFromRemote : false,
12361 * This method is only used by a DataProxy which has retrieved data from a remote server.
12362 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12363 * @return {Object} data A data block which is used by an Roo.data.Store object as
12364 * a cache of Roo.data.Records.
12366 read : function(response){
12367 var json = response.responseText;
12369 var o = /* eval:var:o */ eval("("+json+")");
12371 throw {message: "JsonReader.read: Json object not found"};
12377 this.metaFromRemote = true;
12378 this.meta = o.metaData;
12379 this.recordType = Roo.data.Record.create(o.metaData.fields);
12380 this.onMetaChange(this.meta, this.recordType, o);
12382 return this.readRecords(o);
12385 // private function a store will implement
12386 onMetaChange : function(meta, recordType, o){
12393 simpleAccess: function(obj, subsc) {
12400 getJsonAccessor: function(){
12402 return function(expr) {
12404 return(re.test(expr))
12405 ? new Function("obj", "return obj." + expr)
12410 return Roo.emptyFn;
12415 * Create a data block containing Roo.data.Records from an XML document.
12416 * @param {Object} o An object which contains an Array of row objects in the property specified
12417 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12418 * which contains the total size of the dataset.
12419 * @return {Object} data A data block which is used by an Roo.data.Store object as
12420 * a cache of Roo.data.Records.
12422 readRecords : function(o){
12424 * After any data loads, the raw JSON data is available for further custom processing.
12428 var s = this.meta, Record = this.recordType,
12429 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12431 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12433 if(s.totalProperty) {
12434 this.getTotal = this.getJsonAccessor(s.totalProperty);
12436 if(s.successProperty) {
12437 this.getSuccess = this.getJsonAccessor(s.successProperty);
12439 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12441 var g = this.getJsonAccessor(s.id);
12442 this.getId = function(rec) {
12444 return (r === undefined || r === "") ? null : r;
12447 this.getId = function(){return null;};
12450 for(var jj = 0; jj < fl; jj++){
12452 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12453 this.ef[jj] = this.getJsonAccessor(map);
12457 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12458 if(s.totalProperty){
12459 var vt = parseInt(this.getTotal(o), 10);
12464 if(s.successProperty){
12465 var vs = this.getSuccess(o);
12466 if(vs === false || vs === 'false'){
12471 for(var i = 0; i < c; i++){
12474 var id = this.getId(n);
12475 for(var j = 0; j < fl; j++){
12477 var v = this.ef[j](n);
12479 Roo.log('missing convert for ' + f.name);
12483 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12485 var record = new Record(values, id);
12487 records[i] = record;
12493 totalRecords : totalRecords
12498 * Ext JS Library 1.1.1
12499 * Copyright(c) 2006-2007, Ext JS, LLC.
12501 * Originally Released Under LGPL - original licence link has changed is not relivant.
12504 * <script type="text/javascript">
12508 * @class Roo.data.ArrayReader
12509 * @extends Roo.data.DataReader
12510 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12511 * Each element of that Array represents a row of data fields. The
12512 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12513 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12517 var RecordDef = Roo.data.Record.create([
12518 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12519 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12521 var myReader = new Roo.data.ArrayReader({
12522 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12526 * This would consume an Array like this:
12528 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12530 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12532 * Create a new JsonReader
12533 * @param {Object} meta Metadata configuration options.
12534 * @param {Object} recordType Either an Array of field definition objects
12535 * as specified to {@link Roo.data.Record#create},
12536 * or an {@link Roo.data.Record} object
12537 * created using {@link Roo.data.Record#create}.
12539 Roo.data.ArrayReader = function(meta, recordType){
12540 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12543 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12545 * Create a data block containing Roo.data.Records from an XML document.
12546 * @param {Object} o An Array of row objects which represents the dataset.
12547 * @return {Object} data A data block which is used by an Roo.data.Store object as
12548 * a cache of Roo.data.Records.
12550 readRecords : function(o){
12551 var sid = this.meta ? this.meta.id : null;
12552 var recordType = this.recordType, fields = recordType.prototype.fields;
12555 for(var i = 0; i < root.length; i++){
12558 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12559 for(var j = 0, jlen = fields.length; j < jlen; j++){
12560 var f = fields.items[j];
12561 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12562 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12564 values[f.name] = v;
12566 var record = new recordType(values, id);
12568 records[records.length] = record;
12572 totalRecords : records.length
12581 * @class Roo.bootstrap.ComboBox
12582 * @extends Roo.bootstrap.TriggerField
12583 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12584 * @cfg {Boolean} append (true|false) default false
12585 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12586 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12587 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12588 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12589 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12590 * @cfg {Boolean} animate default true
12591 * @cfg {Boolean} emptyResultText only for touch device
12592 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12593 * @cfg {String} emptyTitle default ''
12595 * Create a new ComboBox.
12596 * @param {Object} config Configuration options
12598 Roo.bootstrap.ComboBox = function(config){
12599 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12603 * Fires when the dropdown list is expanded
12604 * @param {Roo.bootstrap.ComboBox} combo This combo box
12609 * Fires when the dropdown list is collapsed
12610 * @param {Roo.bootstrap.ComboBox} combo This combo box
12614 * @event beforeselect
12615 * Fires before a list item is selected. Return false to cancel the selection.
12616 * @param {Roo.bootstrap.ComboBox} combo This combo box
12617 * @param {Roo.data.Record} record The data record returned from the underlying store
12618 * @param {Number} index The index of the selected item in the dropdown list
12620 'beforeselect' : true,
12623 * Fires when a list item is selected
12624 * @param {Roo.bootstrap.ComboBox} combo This combo box
12625 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12626 * @param {Number} index The index of the selected item in the dropdown list
12630 * @event beforequery
12631 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12632 * The event object passed has these properties:
12633 * @param {Roo.bootstrap.ComboBox} combo This combo box
12634 * @param {String} query The query
12635 * @param {Boolean} forceAll true to force "all" query
12636 * @param {Boolean} cancel true to cancel the query
12637 * @param {Object} e The query event object
12639 'beforequery': true,
12642 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12643 * @param {Roo.bootstrap.ComboBox} combo This combo box
12648 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12649 * @param {Roo.bootstrap.ComboBox} combo This combo box
12650 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12655 * Fires when the remove value from the combobox array
12656 * @param {Roo.bootstrap.ComboBox} combo This combo box
12660 * @event afterremove
12661 * Fires when the remove value from the combobox array
12662 * @param {Roo.bootstrap.ComboBox} combo This combo box
12664 'afterremove' : true,
12666 * @event specialfilter
12667 * Fires when specialfilter
12668 * @param {Roo.bootstrap.ComboBox} combo This combo box
12670 'specialfilter' : true,
12673 * Fires when tick the element
12674 * @param {Roo.bootstrap.ComboBox} combo This combo box
12678 * @event touchviewdisplay
12679 * Fires when touch view require special display (default is using displayField)
12680 * @param {Roo.bootstrap.ComboBox} combo This combo box
12681 * @param {Object} cfg set html .
12683 'touchviewdisplay' : true
12688 this.tickItems = [];
12690 this.selectedIndex = -1;
12691 if(this.mode == 'local'){
12692 if(config.queryDelay === undefined){
12693 this.queryDelay = 10;
12695 if(config.minChars === undefined){
12701 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12704 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12705 * rendering into an Roo.Editor, defaults to false)
12708 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12709 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12712 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12715 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12716 * the dropdown list (defaults to undefined, with no header element)
12720 * @cfg {String/Roo.Template} tpl The template to use to render the output
12724 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12726 listWidth: undefined,
12728 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12729 * mode = 'remote' or 'text' if mode = 'local')
12731 displayField: undefined,
12734 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12735 * mode = 'remote' or 'value' if mode = 'local').
12736 * Note: use of a valueField requires the user make a selection
12737 * in order for a value to be mapped.
12739 valueField: undefined,
12741 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12746 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12747 * field's data value (defaults to the underlying DOM element's name)
12749 hiddenName: undefined,
12751 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12755 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12757 selectedClass: 'active',
12760 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12764 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12765 * anchor positions (defaults to 'tl-bl')
12767 listAlign: 'tl-bl?',
12769 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12773 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12774 * query specified by the allQuery config option (defaults to 'query')
12776 triggerAction: 'query',
12778 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12779 * (defaults to 4, does not apply if editable = false)
12783 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12784 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12788 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12789 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12793 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12794 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12798 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12799 * when editable = true (defaults to false)
12801 selectOnFocus:false,
12803 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12805 queryParam: 'query',
12807 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12808 * when mode = 'remote' (defaults to 'Loading...')
12810 loadingText: 'Loading...',
12812 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12816 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12820 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12821 * traditional select (defaults to true)
12825 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12829 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12833 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12834 * listWidth has a higher value)
12838 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12839 * allow the user to set arbitrary text into the field (defaults to false)
12841 forceSelection:false,
12843 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12844 * if typeAhead = true (defaults to 250)
12846 typeAheadDelay : 250,
12848 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12849 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12851 valueNotFoundText : undefined,
12853 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12855 blockFocus : false,
12858 * @cfg {Boolean} disableClear Disable showing of clear button.
12860 disableClear : false,
12862 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12864 alwaysQuery : false,
12867 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12872 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12874 invalidClass : "has-warning",
12877 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12879 validClass : "has-success",
12882 * @cfg {Boolean} specialFilter (true|false) special filter default false
12884 specialFilter : false,
12887 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12889 mobileTouchView : true,
12892 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12894 useNativeIOS : false,
12896 ios_options : false,
12908 btnPosition : 'right',
12909 triggerList : true,
12910 showToggleBtn : true,
12912 emptyResultText: 'Empty',
12913 triggerText : 'Select',
12916 // element that contains real text value.. (when hidden is used..)
12918 getAutoCreate : function()
12923 * Render classic select for iso
12926 if(Roo.isIOS && this.useNativeIOS){
12927 cfg = this.getAutoCreateNativeIOS();
12935 if(Roo.isTouch && this.mobileTouchView){
12936 cfg = this.getAutoCreateTouchView();
12943 if(!this.tickable){
12944 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12949 * ComboBox with tickable selections
12952 var align = this.labelAlign || this.parentLabelAlign();
12955 cls : 'form-group roo-combobox-tickable' //input-group
12958 var btn_text_select = '';
12959 var btn_text_done = '';
12960 var btn_text_cancel = '';
12962 if (this.btn_text_show) {
12963 btn_text_select = 'Select';
12964 btn_text_done = 'Done';
12965 btn_text_cancel = 'Cancel';
12970 cls : 'tickable-buttons',
12975 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12976 //html : this.triggerText
12977 html: btn_text_select
12983 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12985 html: btn_text_done
12991 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
12993 html: btn_text_cancel
12999 buttons.cn.unshift({
13001 cls: 'roo-select2-search-field-input'
13007 Roo.each(buttons.cn, function(c){
13009 c.cls += ' btn-' + _this.size;
13012 if (_this.disabled) {
13023 cls: 'form-hidden-field'
13027 cls: 'roo-select2-choices',
13031 cls: 'roo-select2-search-field',
13042 cls: 'roo-select2-container input-group roo-select2-container-multi',
13047 // cls: 'typeahead typeahead-long dropdown-menu',
13048 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13053 if(this.hasFeedback && !this.allowBlank){
13057 cls: 'glyphicon form-control-feedback'
13060 combobox.cn.push(feedback);
13064 if (align ==='left' && this.fieldLabel.length) {
13066 cfg.cls += ' roo-form-group-label-left';
13071 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13072 tooltip : 'This field is required'
13077 cls : 'control-label',
13078 html : this.fieldLabel
13090 var labelCfg = cfg.cn[1];
13091 var contentCfg = cfg.cn[2];
13094 if(this.indicatorpos == 'right'){
13100 cls : 'control-label',
13104 html : this.fieldLabel
13108 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13109 tooltip : 'This field is required'
13124 labelCfg = cfg.cn[0];
13125 contentCfg = cfg.cn[1];
13129 if(this.labelWidth > 12){
13130 labelCfg.style = "width: " + this.labelWidth + 'px';
13133 if(this.labelWidth < 13 && this.labelmd == 0){
13134 this.labelmd = this.labelWidth;
13137 if(this.labellg > 0){
13138 labelCfg.cls += ' col-lg-' + this.labellg;
13139 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13142 if(this.labelmd > 0){
13143 labelCfg.cls += ' col-md-' + this.labelmd;
13144 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13147 if(this.labelsm > 0){
13148 labelCfg.cls += ' col-sm-' + this.labelsm;
13149 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13152 if(this.labelxs > 0){
13153 labelCfg.cls += ' col-xs-' + this.labelxs;
13154 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13158 } else if ( this.fieldLabel.length) {
13159 // Roo.log(" label");
13163 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13164 tooltip : 'This field is required'
13168 //cls : 'input-group-addon',
13169 html : this.fieldLabel
13174 if(this.indicatorpos == 'right'){
13178 //cls : 'input-group-addon',
13179 html : this.fieldLabel
13183 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13184 tooltip : 'This field is required'
13193 // Roo.log(" no label && no align");
13200 ['xs','sm','md','lg'].map(function(size){
13201 if (settings[size]) {
13202 cfg.cls += ' col-' + size + '-' + settings[size];
13210 _initEventsCalled : false,
13213 initEvents: function()
13215 if (this._initEventsCalled) { // as we call render... prevent looping...
13218 this._initEventsCalled = true;
13221 throw "can not find store for combo";
13224 this.indicator = this.indicatorEl();
13226 this.store = Roo.factory(this.store, Roo.data);
13227 this.store.parent = this;
13229 // if we are building from html. then this element is so complex, that we can not really
13230 // use the rendered HTML.
13231 // so we have to trash and replace the previous code.
13232 if (Roo.XComponent.build_from_html) {
13233 // remove this element....
13234 var e = this.el.dom, k=0;
13235 while (e ) { e = e.previousSibling; ++k;}
13240 this.rendered = false;
13242 this.render(this.parent().getChildContainer(true), k);
13245 if(Roo.isIOS && this.useNativeIOS){
13246 this.initIOSView();
13254 if(Roo.isTouch && this.mobileTouchView){
13255 this.initTouchView();
13260 this.initTickableEvents();
13264 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13266 if(this.hiddenName){
13268 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13270 this.hiddenField.dom.value =
13271 this.hiddenValue !== undefined ? this.hiddenValue :
13272 this.value !== undefined ? this.value : '';
13274 // prevent input submission
13275 this.el.dom.removeAttribute('name');
13276 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13281 // this.el.dom.setAttribute('autocomplete', 'off');
13284 var cls = 'x-combo-list';
13286 //this.list = new Roo.Layer({
13287 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13293 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13294 _this.list.setWidth(lw);
13297 this.list.on('mouseover', this.onViewOver, this);
13298 this.list.on('mousemove', this.onViewMove, this);
13299 this.list.on('scroll', this.onViewScroll, this);
13302 this.list.swallowEvent('mousewheel');
13303 this.assetHeight = 0;
13306 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13307 this.assetHeight += this.header.getHeight();
13310 this.innerList = this.list.createChild({cls:cls+'-inner'});
13311 this.innerList.on('mouseover', this.onViewOver, this);
13312 this.innerList.on('mousemove', this.onViewMove, this);
13313 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13315 if(this.allowBlank && !this.pageSize && !this.disableClear){
13316 this.footer = this.list.createChild({cls:cls+'-ft'});
13317 this.pageTb = new Roo.Toolbar(this.footer);
13321 this.footer = this.list.createChild({cls:cls+'-ft'});
13322 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13323 {pageSize: this.pageSize});
13327 if (this.pageTb && this.allowBlank && !this.disableClear) {
13329 this.pageTb.add(new Roo.Toolbar.Fill(), {
13330 cls: 'x-btn-icon x-btn-clear',
13332 handler: function()
13335 _this.clearValue();
13336 _this.onSelect(false, -1);
13341 this.assetHeight += this.footer.getHeight();
13346 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13349 this.view = new Roo.View(this.list, this.tpl, {
13350 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13352 //this.view.wrapEl.setDisplayed(false);
13353 this.view.on('click', this.onViewClick, this);
13356 this.store.on('beforeload', this.onBeforeLoad, this);
13357 this.store.on('load', this.onLoad, this);
13358 this.store.on('loadexception', this.onLoadException, this);
13360 if(this.resizable){
13361 this.resizer = new Roo.Resizable(this.list, {
13362 pinned:true, handles:'se'
13364 this.resizer.on('resize', function(r, w, h){
13365 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13366 this.listWidth = w;
13367 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13368 this.restrictHeight();
13370 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13373 if(!this.editable){
13374 this.editable = true;
13375 this.setEditable(false);
13380 if (typeof(this.events.add.listeners) != 'undefined') {
13382 this.addicon = this.wrap.createChild(
13383 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13385 this.addicon.on('click', function(e) {
13386 this.fireEvent('add', this);
13389 if (typeof(this.events.edit.listeners) != 'undefined') {
13391 this.editicon = this.wrap.createChild(
13392 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13393 if (this.addicon) {
13394 this.editicon.setStyle('margin-left', '40px');
13396 this.editicon.on('click', function(e) {
13398 // we fire even if inothing is selected..
13399 this.fireEvent('edit', this, this.lastData );
13405 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13406 "up" : function(e){
13407 this.inKeyMode = true;
13411 "down" : function(e){
13412 if(!this.isExpanded()){
13413 this.onTriggerClick();
13415 this.inKeyMode = true;
13420 "enter" : function(e){
13421 // this.onViewClick();
13425 if(this.fireEvent("specialkey", this, e)){
13426 this.onViewClick(false);
13432 "esc" : function(e){
13436 "tab" : function(e){
13439 if(this.fireEvent("specialkey", this, e)){
13440 this.onViewClick(false);
13448 doRelay : function(foo, bar, hname){
13449 if(hname == 'down' || this.scope.isExpanded()){
13450 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13459 this.queryDelay = Math.max(this.queryDelay || 10,
13460 this.mode == 'local' ? 10 : 250);
13463 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13465 if(this.typeAhead){
13466 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13468 if(this.editable !== false){
13469 this.inputEl().on("keyup", this.onKeyUp, this);
13471 if(this.forceSelection){
13472 this.inputEl().on('blur', this.doForce, this);
13476 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13477 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13481 initTickableEvents: function()
13485 if(this.hiddenName){
13487 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13489 this.hiddenField.dom.value =
13490 this.hiddenValue !== undefined ? this.hiddenValue :
13491 this.value !== undefined ? this.value : '';
13493 // prevent input submission
13494 this.el.dom.removeAttribute('name');
13495 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13500 // this.list = this.el.select('ul.dropdown-menu',true).first();
13502 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13503 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13504 if(this.triggerList){
13505 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13508 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13509 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13511 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13512 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13514 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13515 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13517 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13518 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13519 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13522 this.cancelBtn.hide();
13527 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13528 _this.list.setWidth(lw);
13531 this.list.on('mouseover', this.onViewOver, this);
13532 this.list.on('mousemove', this.onViewMove, this);
13534 this.list.on('scroll', this.onViewScroll, this);
13537 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13540 this.view = new Roo.View(this.list, this.tpl, {
13541 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13544 //this.view.wrapEl.setDisplayed(false);
13545 this.view.on('click', this.onViewClick, this);
13549 this.store.on('beforeload', this.onBeforeLoad, this);
13550 this.store.on('load', this.onLoad, this);
13551 this.store.on('loadexception', this.onLoadException, this);
13554 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13555 "up" : function(e){
13556 this.inKeyMode = true;
13560 "down" : function(e){
13561 this.inKeyMode = true;
13565 "enter" : function(e){
13566 if(this.fireEvent("specialkey", this, e)){
13567 this.onViewClick(false);
13573 "esc" : function(e){
13574 this.onTickableFooterButtonClick(e, false, false);
13577 "tab" : function(e){
13578 this.fireEvent("specialkey", this, e);
13580 this.onTickableFooterButtonClick(e, false, false);
13587 doRelay : function(e, fn, key){
13588 if(this.scope.isExpanded()){
13589 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13598 this.queryDelay = Math.max(this.queryDelay || 10,
13599 this.mode == 'local' ? 10 : 250);
13602 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13604 if(this.typeAhead){
13605 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13608 if(this.editable !== false){
13609 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13612 this.indicator = this.indicatorEl();
13614 if(this.indicator){
13615 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13616 this.indicator.hide();
13621 onDestroy : function(){
13623 this.view.setStore(null);
13624 this.view.el.removeAllListeners();
13625 this.view.el.remove();
13626 this.view.purgeListeners();
13629 this.list.dom.innerHTML = '';
13633 this.store.un('beforeload', this.onBeforeLoad, this);
13634 this.store.un('load', this.onLoad, this);
13635 this.store.un('loadexception', this.onLoadException, this);
13637 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13641 fireKey : function(e){
13642 if(e.isNavKeyPress() && !this.list.isVisible()){
13643 this.fireEvent("specialkey", this, e);
13648 onResize: function(w, h){
13649 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13651 // if(typeof w != 'number'){
13652 // // we do not handle it!?!?
13655 // var tw = this.trigger.getWidth();
13656 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13657 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13659 // this.inputEl().setWidth( this.adjustWidth('input', x));
13661 // //this.trigger.setStyle('left', x+'px');
13663 // if(this.list && this.listWidth === undefined){
13664 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13665 // this.list.setWidth(lw);
13666 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13674 * Allow or prevent the user from directly editing the field text. If false is passed,
13675 * the user will only be able to select from the items defined in the dropdown list. This method
13676 * is the runtime equivalent of setting the 'editable' config option at config time.
13677 * @param {Boolean} value True to allow the user to directly edit the field text
13679 setEditable : function(value){
13680 if(value == this.editable){
13683 this.editable = value;
13685 this.inputEl().dom.setAttribute('readOnly', true);
13686 this.inputEl().on('mousedown', this.onTriggerClick, this);
13687 this.inputEl().addClass('x-combo-noedit');
13689 this.inputEl().dom.setAttribute('readOnly', false);
13690 this.inputEl().un('mousedown', this.onTriggerClick, this);
13691 this.inputEl().removeClass('x-combo-noedit');
13697 onBeforeLoad : function(combo,opts){
13698 if(!this.hasFocus){
13702 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13704 this.restrictHeight();
13705 this.selectedIndex = -1;
13709 onLoad : function(){
13711 this.hasQuery = false;
13713 if(!this.hasFocus){
13717 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13718 this.loading.hide();
13721 if(this.store.getCount() > 0){
13724 this.restrictHeight();
13725 if(this.lastQuery == this.allQuery){
13726 if(this.editable && !this.tickable){
13727 this.inputEl().dom.select();
13731 !this.selectByValue(this.value, true) &&
13734 !this.store.lastOptions ||
13735 typeof(this.store.lastOptions.add) == 'undefined' ||
13736 this.store.lastOptions.add != true
13739 this.select(0, true);
13742 if(this.autoFocus){
13745 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13746 this.taTask.delay(this.typeAheadDelay);
13750 this.onEmptyResults();
13756 onLoadException : function()
13758 this.hasQuery = false;
13760 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13761 this.loading.hide();
13764 if(this.tickable && this.editable){
13769 // only causes errors at present
13770 //Roo.log(this.store.reader.jsonData);
13771 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13773 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13779 onTypeAhead : function(){
13780 if(this.store.getCount() > 0){
13781 var r = this.store.getAt(0);
13782 var newValue = r.data[this.displayField];
13783 var len = newValue.length;
13784 var selStart = this.getRawValue().length;
13786 if(selStart != len){
13787 this.setRawValue(newValue);
13788 this.selectText(selStart, newValue.length);
13794 onSelect : function(record, index){
13796 if(this.fireEvent('beforeselect', this, record, index) !== false){
13798 this.setFromData(index > -1 ? record.data : false);
13801 this.fireEvent('select', this, record, index);
13806 * Returns the currently selected field value or empty string if no value is set.
13807 * @return {String} value The selected value
13809 getValue : function()
13811 if(Roo.isIOS && this.useNativeIOS){
13812 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13816 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13819 if(this.valueField){
13820 return typeof this.value != 'undefined' ? this.value : '';
13822 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13826 getRawValue : function()
13828 if(Roo.isIOS && this.useNativeIOS){
13829 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13832 var v = this.inputEl().getValue();
13838 * Clears any text/value currently set in the field
13840 clearValue : function(){
13842 if(this.hiddenField){
13843 this.hiddenField.dom.value = '';
13846 this.setRawValue('');
13847 this.lastSelectionText = '';
13848 this.lastData = false;
13850 var close = this.closeTriggerEl();
13861 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13862 * will be displayed in the field. If the value does not match the data value of an existing item,
13863 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13864 * Otherwise the field will be blank (although the value will still be set).
13865 * @param {String} value The value to match
13867 setValue : function(v)
13869 if(Roo.isIOS && this.useNativeIOS){
13870 this.setIOSValue(v);
13880 if(this.valueField){
13881 var r = this.findRecord(this.valueField, v);
13883 text = r.data[this.displayField];
13884 }else if(this.valueNotFoundText !== undefined){
13885 text = this.valueNotFoundText;
13888 this.lastSelectionText = text;
13889 if(this.hiddenField){
13890 this.hiddenField.dom.value = v;
13892 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13895 var close = this.closeTriggerEl();
13898 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13904 * @property {Object} the last set data for the element
13909 * Sets the value of the field based on a object which is related to the record format for the store.
13910 * @param {Object} value the value to set as. or false on reset?
13912 setFromData : function(o){
13919 var dv = ''; // display value
13920 var vv = ''; // value value..
13922 if (this.displayField) {
13923 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13925 // this is an error condition!!!
13926 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13929 if(this.valueField){
13930 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13933 var close = this.closeTriggerEl();
13936 if(dv.length || vv * 1 > 0){
13938 this.blockFocus=true;
13944 if(this.hiddenField){
13945 this.hiddenField.dom.value = vv;
13947 this.lastSelectionText = dv;
13948 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13952 // no hidden field.. - we store the value in 'value', but still display
13953 // display field!!!!
13954 this.lastSelectionText = dv;
13955 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13962 reset : function(){
13963 // overridden so that last data is reset..
13970 this.setValue(this.originalValue);
13971 //this.clearInvalid();
13972 this.lastData = false;
13974 this.view.clearSelections();
13980 findRecord : function(prop, value){
13982 if(this.store.getCount() > 0){
13983 this.store.each(function(r){
13984 if(r.data[prop] == value){
13994 getName: function()
13996 // returns hidden if it's set..
13997 if (!this.rendered) {return ''};
13998 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14002 onViewMove : function(e, t){
14003 this.inKeyMode = false;
14007 onViewOver : function(e, t){
14008 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14011 var item = this.view.findItemFromChild(t);
14014 var index = this.view.indexOf(item);
14015 this.select(index, false);
14020 onViewClick : function(view, doFocus, el, e)
14022 var index = this.view.getSelectedIndexes()[0];
14024 var r = this.store.getAt(index);
14028 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14035 Roo.each(this.tickItems, function(v,k){
14037 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14039 _this.tickItems.splice(k, 1);
14041 if(typeof(e) == 'undefined' && view == false){
14042 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14054 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14055 this.tickItems.push(r.data);
14058 if(typeof(e) == 'undefined' && view == false){
14059 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14066 this.onSelect(r, index);
14068 if(doFocus !== false && !this.blockFocus){
14069 this.inputEl().focus();
14074 restrictHeight : function(){
14075 //this.innerList.dom.style.height = '';
14076 //var inner = this.innerList.dom;
14077 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14078 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14079 //this.list.beginUpdate();
14080 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14081 this.list.alignTo(this.inputEl(), this.listAlign);
14082 this.list.alignTo(this.inputEl(), this.listAlign);
14083 //this.list.endUpdate();
14087 onEmptyResults : function(){
14089 if(this.tickable && this.editable){
14090 this.hasFocus = false;
14091 this.restrictHeight();
14099 * Returns true if the dropdown list is expanded, else false.
14101 isExpanded : function(){
14102 return this.list.isVisible();
14106 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14107 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14108 * @param {String} value The data value of the item to select
14109 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14110 * selected item if it is not currently in view (defaults to true)
14111 * @return {Boolean} True if the value matched an item in the list, else false
14113 selectByValue : function(v, scrollIntoView){
14114 if(v !== undefined && v !== null){
14115 var r = this.findRecord(this.valueField || this.displayField, v);
14117 this.select(this.store.indexOf(r), scrollIntoView);
14125 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14126 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14127 * @param {Number} index The zero-based index of the list item to select
14128 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14129 * selected item if it is not currently in view (defaults to true)
14131 select : function(index, scrollIntoView){
14132 this.selectedIndex = index;
14133 this.view.select(index);
14134 if(scrollIntoView !== false){
14135 var el = this.view.getNode(index);
14137 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14140 this.list.scrollChildIntoView(el, false);
14146 selectNext : function(){
14147 var ct = this.store.getCount();
14149 if(this.selectedIndex == -1){
14151 }else if(this.selectedIndex < ct-1){
14152 this.select(this.selectedIndex+1);
14158 selectPrev : function(){
14159 var ct = this.store.getCount();
14161 if(this.selectedIndex == -1){
14163 }else if(this.selectedIndex != 0){
14164 this.select(this.selectedIndex-1);
14170 onKeyUp : function(e){
14171 if(this.editable !== false && !e.isSpecialKey()){
14172 this.lastKey = e.getKey();
14173 this.dqTask.delay(this.queryDelay);
14178 validateBlur : function(){
14179 return !this.list || !this.list.isVisible();
14183 initQuery : function(){
14185 var v = this.getRawValue();
14187 if(this.tickable && this.editable){
14188 v = this.tickableInputEl().getValue();
14195 doForce : function(){
14196 if(this.inputEl().dom.value.length > 0){
14197 this.inputEl().dom.value =
14198 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14204 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14205 * query allowing the query action to be canceled if needed.
14206 * @param {String} query The SQL query to execute
14207 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14208 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14209 * saved in the current store (defaults to false)
14211 doQuery : function(q, forceAll){
14213 if(q === undefined || q === null){
14218 forceAll: forceAll,
14222 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14227 forceAll = qe.forceAll;
14228 if(forceAll === true || (q.length >= this.minChars)){
14230 this.hasQuery = true;
14232 if(this.lastQuery != q || this.alwaysQuery){
14233 this.lastQuery = q;
14234 if(this.mode == 'local'){
14235 this.selectedIndex = -1;
14237 this.store.clearFilter();
14240 if(this.specialFilter){
14241 this.fireEvent('specialfilter', this);
14246 this.store.filter(this.displayField, q);
14249 this.store.fireEvent("datachanged", this.store);
14256 this.store.baseParams[this.queryParam] = q;
14258 var options = {params : this.getParams(q)};
14261 options.add = true;
14262 options.params.start = this.page * this.pageSize;
14265 this.store.load(options);
14268 * this code will make the page width larger, at the beginning, the list not align correctly,
14269 * we should expand the list on onLoad
14270 * so command out it
14275 this.selectedIndex = -1;
14280 this.loadNext = false;
14284 getParams : function(q){
14286 //p[this.queryParam] = q;
14290 p.limit = this.pageSize;
14296 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14298 collapse : function(){
14299 if(!this.isExpanded()){
14305 this.hasFocus = false;
14309 this.cancelBtn.hide();
14310 this.trigger.show();
14313 this.tickableInputEl().dom.value = '';
14314 this.tickableInputEl().blur();
14319 Roo.get(document).un('mousedown', this.collapseIf, this);
14320 Roo.get(document).un('mousewheel', this.collapseIf, this);
14321 if (!this.editable) {
14322 Roo.get(document).un('keydown', this.listKeyPress, this);
14324 this.fireEvent('collapse', this);
14330 collapseIf : function(e){
14331 var in_combo = e.within(this.el);
14332 var in_list = e.within(this.list);
14333 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14335 if (in_combo || in_list || is_list) {
14336 //e.stopPropagation();
14341 this.onTickableFooterButtonClick(e, false, false);
14349 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14351 expand : function(){
14353 if(this.isExpanded() || !this.hasFocus){
14357 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14358 this.list.setWidth(lw);
14364 this.restrictHeight();
14368 this.tickItems = Roo.apply([], this.item);
14371 this.cancelBtn.show();
14372 this.trigger.hide();
14375 this.tickableInputEl().focus();
14380 Roo.get(document).on('mousedown', this.collapseIf, this);
14381 Roo.get(document).on('mousewheel', this.collapseIf, this);
14382 if (!this.editable) {
14383 Roo.get(document).on('keydown', this.listKeyPress, this);
14386 this.fireEvent('expand', this);
14390 // Implements the default empty TriggerField.onTriggerClick function
14391 onTriggerClick : function(e)
14393 Roo.log('trigger click');
14395 if(this.disabled || !this.triggerList){
14400 this.loadNext = false;
14402 if(this.isExpanded()){
14404 if (!this.blockFocus) {
14405 this.inputEl().focus();
14409 this.hasFocus = true;
14410 if(this.triggerAction == 'all') {
14411 this.doQuery(this.allQuery, true);
14413 this.doQuery(this.getRawValue());
14415 if (!this.blockFocus) {
14416 this.inputEl().focus();
14421 onTickableTriggerClick : function(e)
14428 this.loadNext = false;
14429 this.hasFocus = true;
14431 if(this.triggerAction == 'all') {
14432 this.doQuery(this.allQuery, true);
14434 this.doQuery(this.getRawValue());
14438 onSearchFieldClick : function(e)
14440 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14441 this.onTickableFooterButtonClick(e, false, false);
14445 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14450 this.loadNext = false;
14451 this.hasFocus = true;
14453 if(this.triggerAction == 'all') {
14454 this.doQuery(this.allQuery, true);
14456 this.doQuery(this.getRawValue());
14460 listKeyPress : function(e)
14462 //Roo.log('listkeypress');
14463 // scroll to first matching element based on key pres..
14464 if (e.isSpecialKey()) {
14467 var k = String.fromCharCode(e.getKey()).toUpperCase();
14470 var csel = this.view.getSelectedNodes();
14471 var cselitem = false;
14473 var ix = this.view.indexOf(csel[0]);
14474 cselitem = this.store.getAt(ix);
14475 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14481 this.store.each(function(v) {
14483 // start at existing selection.
14484 if (cselitem.id == v.id) {
14490 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14491 match = this.store.indexOf(v);
14497 if (match === false) {
14498 return true; // no more action?
14501 this.view.select(match);
14502 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14503 sn.scrollIntoView(sn.dom.parentNode, false);
14506 onViewScroll : function(e, t){
14508 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){
14512 this.hasQuery = true;
14514 this.loading = this.list.select('.loading', true).first();
14516 if(this.loading === null){
14517 this.list.createChild({
14519 cls: 'loading roo-select2-more-results roo-select2-active',
14520 html: 'Loading more results...'
14523 this.loading = this.list.select('.loading', true).first();
14525 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14527 this.loading.hide();
14530 this.loading.show();
14535 this.loadNext = true;
14537 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14542 addItem : function(o)
14544 var dv = ''; // display value
14546 if (this.displayField) {
14547 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14549 // this is an error condition!!!
14550 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14557 var choice = this.choices.createChild({
14559 cls: 'roo-select2-search-choice',
14568 cls: 'roo-select2-search-choice-close fa fa-times',
14573 }, this.searchField);
14575 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14577 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14585 this.inputEl().dom.value = '';
14590 onRemoveItem : function(e, _self, o)
14592 e.preventDefault();
14594 this.lastItem = Roo.apply([], this.item);
14596 var index = this.item.indexOf(o.data) * 1;
14599 Roo.log('not this item?!');
14603 this.item.splice(index, 1);
14608 this.fireEvent('remove', this, e);
14614 syncValue : function()
14616 if(!this.item.length){
14623 Roo.each(this.item, function(i){
14624 if(_this.valueField){
14625 value.push(i[_this.valueField]);
14632 this.value = value.join(',');
14634 if(this.hiddenField){
14635 this.hiddenField.dom.value = this.value;
14638 this.store.fireEvent("datachanged", this.store);
14643 clearItem : function()
14645 if(!this.multiple){
14651 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14659 if(this.tickable && !Roo.isTouch){
14660 this.view.refresh();
14664 inputEl: function ()
14666 if(Roo.isIOS && this.useNativeIOS){
14667 return this.el.select('select.roo-ios-select', true).first();
14670 if(Roo.isTouch && this.mobileTouchView){
14671 return this.el.select('input.form-control',true).first();
14675 return this.searchField;
14678 return this.el.select('input.form-control',true).first();
14681 onTickableFooterButtonClick : function(e, btn, el)
14683 e.preventDefault();
14685 this.lastItem = Roo.apply([], this.item);
14687 if(btn && btn.name == 'cancel'){
14688 this.tickItems = Roo.apply([], this.item);
14697 Roo.each(this.tickItems, function(o){
14705 validate : function()
14707 if(this.getEl().hasClass('hidden')){
14711 var v = this.getRawValue();
14714 v = this.getValue();
14717 if(this.disabled || this.allowBlank || v.length){
14722 this.markInvalid();
14726 tickableInputEl : function()
14728 if(!this.tickable || !this.editable){
14729 return this.inputEl();
14732 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14736 getAutoCreateTouchView : function()
14741 cls: 'form-group' //input-group
14747 type : this.inputType,
14748 cls : 'form-control x-combo-noedit',
14749 autocomplete: 'new-password',
14750 placeholder : this.placeholder || '',
14755 input.name = this.name;
14759 input.cls += ' input-' + this.size;
14762 if (this.disabled) {
14763 input.disabled = true;
14774 inputblock.cls += ' input-group';
14776 inputblock.cn.unshift({
14778 cls : 'input-group-addon',
14783 if(this.removable && !this.multiple){
14784 inputblock.cls += ' roo-removable';
14786 inputblock.cn.push({
14789 cls : 'roo-combo-removable-btn close'
14793 if(this.hasFeedback && !this.allowBlank){
14795 inputblock.cls += ' has-feedback';
14797 inputblock.cn.push({
14799 cls: 'glyphicon form-control-feedback'
14806 inputblock.cls += (this.before) ? '' : ' input-group';
14808 inputblock.cn.push({
14810 cls : 'input-group-addon',
14821 cls: 'form-hidden-field'
14835 cls: 'form-hidden-field'
14839 cls: 'roo-select2-choices',
14843 cls: 'roo-select2-search-field',
14856 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14862 if(!this.multiple && this.showToggleBtn){
14869 if (this.caret != false) {
14872 cls: 'fa fa-' + this.caret
14879 cls : 'input-group-addon btn dropdown-toggle',
14884 cls: 'combobox-clear',
14898 combobox.cls += ' roo-select2-container-multi';
14901 var align = this.labelAlign || this.parentLabelAlign();
14903 if (align ==='left' && this.fieldLabel.length) {
14908 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14909 tooltip : 'This field is required'
14913 cls : 'control-label',
14914 html : this.fieldLabel
14925 var labelCfg = cfg.cn[1];
14926 var contentCfg = cfg.cn[2];
14929 if(this.indicatorpos == 'right'){
14934 cls : 'control-label',
14938 html : this.fieldLabel
14942 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14943 tooltip : 'This field is required'
14956 labelCfg = cfg.cn[0];
14957 contentCfg = cfg.cn[1];
14962 if(this.labelWidth > 12){
14963 labelCfg.style = "width: " + this.labelWidth + 'px';
14966 if(this.labelWidth < 13 && this.labelmd == 0){
14967 this.labelmd = this.labelWidth;
14970 if(this.labellg > 0){
14971 labelCfg.cls += ' col-lg-' + this.labellg;
14972 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14975 if(this.labelmd > 0){
14976 labelCfg.cls += ' col-md-' + this.labelmd;
14977 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14980 if(this.labelsm > 0){
14981 labelCfg.cls += ' col-sm-' + this.labelsm;
14982 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14985 if(this.labelxs > 0){
14986 labelCfg.cls += ' col-xs-' + this.labelxs;
14987 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
14991 } else if ( this.fieldLabel.length) {
14995 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14996 tooltip : 'This field is required'
15000 cls : 'control-label',
15001 html : this.fieldLabel
15012 if(this.indicatorpos == 'right'){
15016 cls : 'control-label',
15017 html : this.fieldLabel,
15021 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15022 tooltip : 'This field is required'
15039 var settings = this;
15041 ['xs','sm','md','lg'].map(function(size){
15042 if (settings[size]) {
15043 cfg.cls += ' col-' + size + '-' + settings[size];
15050 initTouchView : function()
15052 this.renderTouchView();
15054 this.touchViewEl.on('scroll', function(){
15055 this.el.dom.scrollTop = 0;
15058 this.originalValue = this.getValue();
15060 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15062 this.inputEl().on("click", this.showTouchView, this);
15063 if (this.triggerEl) {
15064 this.triggerEl.on("click", this.showTouchView, this);
15068 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15069 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15071 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15073 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15074 this.store.on('load', this.onTouchViewLoad, this);
15075 this.store.on('loadexception', this.onTouchViewLoadException, this);
15077 if(this.hiddenName){
15079 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15081 this.hiddenField.dom.value =
15082 this.hiddenValue !== undefined ? this.hiddenValue :
15083 this.value !== undefined ? this.value : '';
15085 this.el.dom.removeAttribute('name');
15086 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15090 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15091 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15094 if(this.removable && !this.multiple){
15095 var close = this.closeTriggerEl();
15097 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15098 close.on('click', this.removeBtnClick, this, close);
15102 * fix the bug in Safari iOS8
15104 this.inputEl().on("focus", function(e){
15105 document.activeElement.blur();
15113 renderTouchView : function()
15115 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15116 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15118 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15119 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15121 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15122 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15123 this.touchViewBodyEl.setStyle('overflow', 'auto');
15125 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15126 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15128 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15129 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15133 showTouchView : function()
15139 this.touchViewHeaderEl.hide();
15141 if(this.modalTitle.length){
15142 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15143 this.touchViewHeaderEl.show();
15146 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15147 this.touchViewEl.show();
15149 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15151 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15152 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15154 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15156 if(this.modalTitle.length){
15157 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15160 this.touchViewBodyEl.setHeight(bodyHeight);
15164 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15166 this.touchViewEl.addClass('in');
15169 this.doTouchViewQuery();
15173 hideTouchView : function()
15175 this.touchViewEl.removeClass('in');
15179 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15181 this.touchViewEl.setStyle('display', 'none');
15186 setTouchViewValue : function()
15193 Roo.each(this.tickItems, function(o){
15198 this.hideTouchView();
15201 doTouchViewQuery : function()
15210 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15214 if(!this.alwaysQuery || this.mode == 'local'){
15215 this.onTouchViewLoad();
15222 onTouchViewBeforeLoad : function(combo,opts)
15228 onTouchViewLoad : function()
15230 if(this.store.getCount() < 1){
15231 this.onTouchViewEmptyResults();
15235 this.clearTouchView();
15237 var rawValue = this.getRawValue();
15239 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15241 this.tickItems = [];
15243 this.store.data.each(function(d, rowIndex){
15244 var row = this.touchViewListGroup.createChild(template);
15246 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15247 row.addClass(d.data.cls);
15250 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15253 html : d.data[this.displayField]
15256 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15257 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15260 row.removeClass('selected');
15261 if(!this.multiple && this.valueField &&
15262 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15265 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15266 row.addClass('selected');
15269 if(this.multiple && this.valueField &&
15270 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15274 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15275 this.tickItems.push(d.data);
15278 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15282 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15284 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15286 if(this.modalTitle.length){
15287 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15290 var listHeight = this.touchViewListGroup.getHeight();
15294 if(firstChecked && listHeight > bodyHeight){
15295 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15300 onTouchViewLoadException : function()
15302 this.hideTouchView();
15305 onTouchViewEmptyResults : function()
15307 this.clearTouchView();
15309 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15311 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15315 clearTouchView : function()
15317 this.touchViewListGroup.dom.innerHTML = '';
15320 onTouchViewClick : function(e, el, o)
15322 e.preventDefault();
15325 var rowIndex = o.rowIndex;
15327 var r = this.store.getAt(rowIndex);
15329 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15331 if(!this.multiple){
15332 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15333 c.dom.removeAttribute('checked');
15336 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15338 this.setFromData(r.data);
15340 var close = this.closeTriggerEl();
15346 this.hideTouchView();
15348 this.fireEvent('select', this, r, rowIndex);
15353 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15354 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15355 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15359 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15360 this.addItem(r.data);
15361 this.tickItems.push(r.data);
15365 getAutoCreateNativeIOS : function()
15368 cls: 'form-group' //input-group,
15373 cls : 'roo-ios-select'
15377 combobox.name = this.name;
15380 if (this.disabled) {
15381 combobox.disabled = true;
15384 var settings = this;
15386 ['xs','sm','md','lg'].map(function(size){
15387 if (settings[size]) {
15388 cfg.cls += ' col-' + size + '-' + settings[size];
15398 initIOSView : function()
15400 this.store.on('load', this.onIOSViewLoad, this);
15405 onIOSViewLoad : function()
15407 if(this.store.getCount() < 1){
15411 this.clearIOSView();
15413 if(this.allowBlank) {
15415 var default_text = '-- SELECT --';
15417 if(this.placeholder.length){
15418 default_text = this.placeholder;
15421 if(this.emptyTitle.length){
15422 default_text += ' - ' + this.emptyTitle + ' -';
15425 var opt = this.inputEl().createChild({
15428 html : default_text
15432 o[this.valueField] = 0;
15433 o[this.displayField] = default_text;
15435 this.ios_options.push({
15442 this.store.data.each(function(d, rowIndex){
15446 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15447 html = d.data[this.displayField];
15452 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15453 value = d.data[this.valueField];
15462 if(this.value == d.data[this.valueField]){
15463 option['selected'] = true;
15466 var opt = this.inputEl().createChild(option);
15468 this.ios_options.push({
15475 this.inputEl().on('change', function(){
15476 this.fireEvent('select', this);
15481 clearIOSView: function()
15483 this.inputEl().dom.innerHTML = '';
15485 this.ios_options = [];
15488 setIOSValue: function(v)
15492 if(!this.ios_options){
15496 Roo.each(this.ios_options, function(opts){
15498 opts.el.dom.removeAttribute('selected');
15500 if(opts.data[this.valueField] != v){
15504 opts.el.dom.setAttribute('selected', true);
15510 * @cfg {Boolean} grow
15514 * @cfg {Number} growMin
15518 * @cfg {Number} growMax
15527 Roo.apply(Roo.bootstrap.ComboBox, {
15531 cls: 'modal-header',
15553 cls: 'list-group-item',
15557 cls: 'roo-combobox-list-group-item-value'
15561 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15575 listItemCheckbox : {
15577 cls: 'list-group-item',
15581 cls: 'roo-combobox-list-group-item-value'
15585 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15601 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15606 cls: 'modal-footer',
15614 cls: 'col-xs-6 text-left',
15617 cls: 'btn btn-danger roo-touch-view-cancel',
15623 cls: 'col-xs-6 text-right',
15626 cls: 'btn btn-success roo-touch-view-ok',
15637 Roo.apply(Roo.bootstrap.ComboBox, {
15639 touchViewTemplate : {
15641 cls: 'modal fade roo-combobox-touch-view',
15645 cls: 'modal-dialog',
15646 style : 'position:fixed', // we have to fix position....
15650 cls: 'modal-content',
15652 Roo.bootstrap.ComboBox.header,
15653 Roo.bootstrap.ComboBox.body,
15654 Roo.bootstrap.ComboBox.footer
15663 * Ext JS Library 1.1.1
15664 * Copyright(c) 2006-2007, Ext JS, LLC.
15666 * Originally Released Under LGPL - original licence link has changed is not relivant.
15669 * <script type="text/javascript">
15674 * @extends Roo.util.Observable
15675 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15676 * This class also supports single and multi selection modes. <br>
15677 * Create a data model bound view:
15679 var store = new Roo.data.Store(...);
15681 var view = new Roo.View({
15683 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15685 singleSelect: true,
15686 selectedClass: "ydataview-selected",
15690 // listen for node click?
15691 view.on("click", function(vw, index, node, e){
15692 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15696 dataModel.load("foobar.xml");
15698 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15700 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15701 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15703 * Note: old style constructor is still suported (container, template, config)
15706 * Create a new View
15707 * @param {Object} config The config object
15710 Roo.View = function(config, depreciated_tpl, depreciated_config){
15712 this.parent = false;
15714 if (typeof(depreciated_tpl) == 'undefined') {
15715 // new way.. - universal constructor.
15716 Roo.apply(this, config);
15717 this.el = Roo.get(this.el);
15720 this.el = Roo.get(config);
15721 this.tpl = depreciated_tpl;
15722 Roo.apply(this, depreciated_config);
15724 this.wrapEl = this.el.wrap().wrap();
15725 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15728 if(typeof(this.tpl) == "string"){
15729 this.tpl = new Roo.Template(this.tpl);
15731 // support xtype ctors..
15732 this.tpl = new Roo.factory(this.tpl, Roo);
15736 this.tpl.compile();
15741 * @event beforeclick
15742 * Fires before a click is processed. Returns false to cancel the default action.
15743 * @param {Roo.View} this
15744 * @param {Number} index The index of the target node
15745 * @param {HTMLElement} node The target node
15746 * @param {Roo.EventObject} e The raw event object
15748 "beforeclick" : true,
15751 * Fires when a template node is clicked.
15752 * @param {Roo.View} this
15753 * @param {Number} index The index of the target node
15754 * @param {HTMLElement} node The target node
15755 * @param {Roo.EventObject} e The raw event object
15760 * Fires when a template node is double clicked.
15761 * @param {Roo.View} this
15762 * @param {Number} index The index of the target node
15763 * @param {HTMLElement} node The target node
15764 * @param {Roo.EventObject} e The raw event object
15768 * @event contextmenu
15769 * Fires when a template node is right clicked.
15770 * @param {Roo.View} this
15771 * @param {Number} index The index of the target node
15772 * @param {HTMLElement} node The target node
15773 * @param {Roo.EventObject} e The raw event object
15775 "contextmenu" : true,
15777 * @event selectionchange
15778 * Fires when the selected nodes change.
15779 * @param {Roo.View} this
15780 * @param {Array} selections Array of the selected nodes
15782 "selectionchange" : true,
15785 * @event beforeselect
15786 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15787 * @param {Roo.View} this
15788 * @param {HTMLElement} node The node to be selected
15789 * @param {Array} selections Array of currently selected nodes
15791 "beforeselect" : true,
15793 * @event preparedata
15794 * Fires on every row to render, to allow you to change the data.
15795 * @param {Roo.View} this
15796 * @param {Object} data to be rendered (change this)
15798 "preparedata" : true
15806 "click": this.onClick,
15807 "dblclick": this.onDblClick,
15808 "contextmenu": this.onContextMenu,
15812 this.selections = [];
15814 this.cmp = new Roo.CompositeElementLite([]);
15816 this.store = Roo.factory(this.store, Roo.data);
15817 this.setStore(this.store, true);
15820 if ( this.footer && this.footer.xtype) {
15822 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15824 this.footer.dataSource = this.store;
15825 this.footer.container = fctr;
15826 this.footer = Roo.factory(this.footer, Roo);
15827 fctr.insertFirst(this.el);
15829 // this is a bit insane - as the paging toolbar seems to detach the el..
15830 // dom.parentNode.parentNode.parentNode
15831 // they get detached?
15835 Roo.View.superclass.constructor.call(this);
15840 Roo.extend(Roo.View, Roo.util.Observable, {
15843 * @cfg {Roo.data.Store} store Data store to load data from.
15848 * @cfg {String|Roo.Element} el The container element.
15853 * @cfg {String|Roo.Template} tpl The template used by this View
15857 * @cfg {String} dataName the named area of the template to use as the data area
15858 * Works with domtemplates roo-name="name"
15862 * @cfg {String} selectedClass The css class to add to selected nodes
15864 selectedClass : "x-view-selected",
15866 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15871 * @cfg {String} text to display on mask (default Loading)
15875 * @cfg {Boolean} multiSelect Allow multiple selection
15877 multiSelect : false,
15879 * @cfg {Boolean} singleSelect Allow single selection
15881 singleSelect: false,
15884 * @cfg {Boolean} toggleSelect - selecting
15886 toggleSelect : false,
15889 * @cfg {Boolean} tickable - selecting
15894 * Returns the element this view is bound to.
15895 * @return {Roo.Element}
15897 getEl : function(){
15898 return this.wrapEl;
15904 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15906 refresh : function(){
15907 //Roo.log('refresh');
15910 // if we are using something like 'domtemplate', then
15911 // the what gets used is:
15912 // t.applySubtemplate(NAME, data, wrapping data..)
15913 // the outer template then get' applied with
15914 // the store 'extra data'
15915 // and the body get's added to the
15916 // roo-name="data" node?
15917 // <span class='roo-tpl-{name}'></span> ?????
15921 this.clearSelections();
15922 this.el.update("");
15924 var records = this.store.getRange();
15925 if(records.length < 1) {
15927 // is this valid?? = should it render a template??
15929 this.el.update(this.emptyText);
15933 if (this.dataName) {
15934 this.el.update(t.apply(this.store.meta)); //????
15935 el = this.el.child('.roo-tpl-' + this.dataName);
15938 for(var i = 0, len = records.length; i < len; i++){
15939 var data = this.prepareData(records[i].data, i, records[i]);
15940 this.fireEvent("preparedata", this, data, i, records[i]);
15942 var d = Roo.apply({}, data);
15945 Roo.apply(d, {'roo-id' : Roo.id()});
15949 Roo.each(this.parent.item, function(item){
15950 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15953 Roo.apply(d, {'roo-data-checked' : 'checked'});
15957 html[html.length] = Roo.util.Format.trim(
15959 t.applySubtemplate(this.dataName, d, this.store.meta) :
15966 el.update(html.join(""));
15967 this.nodes = el.dom.childNodes;
15968 this.updateIndexes(0);
15973 * Function to override to reformat the data that is sent to
15974 * the template for each node.
15975 * DEPRICATED - use the preparedata event handler.
15976 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15977 * a JSON object for an UpdateManager bound view).
15979 prepareData : function(data, index, record)
15981 this.fireEvent("preparedata", this, data, index, record);
15985 onUpdate : function(ds, record){
15986 // Roo.log('on update');
15987 this.clearSelections();
15988 var index = this.store.indexOf(record);
15989 var n = this.nodes[index];
15990 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
15991 n.parentNode.removeChild(n);
15992 this.updateIndexes(index, index);
15998 onAdd : function(ds, records, index)
16000 //Roo.log(['on Add', ds, records, index] );
16001 this.clearSelections();
16002 if(this.nodes.length == 0){
16006 var n = this.nodes[index];
16007 for(var i = 0, len = records.length; i < len; i++){
16008 var d = this.prepareData(records[i].data, i, records[i]);
16010 this.tpl.insertBefore(n, d);
16013 this.tpl.append(this.el, d);
16016 this.updateIndexes(index);
16019 onRemove : function(ds, record, index){
16020 // Roo.log('onRemove');
16021 this.clearSelections();
16022 var el = this.dataName ?
16023 this.el.child('.roo-tpl-' + this.dataName) :
16026 el.dom.removeChild(this.nodes[index]);
16027 this.updateIndexes(index);
16031 * Refresh an individual node.
16032 * @param {Number} index
16034 refreshNode : function(index){
16035 this.onUpdate(this.store, this.store.getAt(index));
16038 updateIndexes : function(startIndex, endIndex){
16039 var ns = this.nodes;
16040 startIndex = startIndex || 0;
16041 endIndex = endIndex || ns.length - 1;
16042 for(var i = startIndex; i <= endIndex; i++){
16043 ns[i].nodeIndex = i;
16048 * Changes the data store this view uses and refresh the view.
16049 * @param {Store} store
16051 setStore : function(store, initial){
16052 if(!initial && this.store){
16053 this.store.un("datachanged", this.refresh);
16054 this.store.un("add", this.onAdd);
16055 this.store.un("remove", this.onRemove);
16056 this.store.un("update", this.onUpdate);
16057 this.store.un("clear", this.refresh);
16058 this.store.un("beforeload", this.onBeforeLoad);
16059 this.store.un("load", this.onLoad);
16060 this.store.un("loadexception", this.onLoad);
16064 store.on("datachanged", this.refresh, this);
16065 store.on("add", this.onAdd, this);
16066 store.on("remove", this.onRemove, this);
16067 store.on("update", this.onUpdate, this);
16068 store.on("clear", this.refresh, this);
16069 store.on("beforeload", this.onBeforeLoad, this);
16070 store.on("load", this.onLoad, this);
16071 store.on("loadexception", this.onLoad, this);
16079 * onbeforeLoad - masks the loading area.
16082 onBeforeLoad : function(store,opts)
16084 //Roo.log('onBeforeLoad');
16086 this.el.update("");
16088 this.el.mask(this.mask ? this.mask : "Loading" );
16090 onLoad : function ()
16097 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16098 * @param {HTMLElement} node
16099 * @return {HTMLElement} The template node
16101 findItemFromChild : function(node){
16102 var el = this.dataName ?
16103 this.el.child('.roo-tpl-' + this.dataName,true) :
16106 if(!node || node.parentNode == el){
16109 var p = node.parentNode;
16110 while(p && p != el){
16111 if(p.parentNode == el){
16120 onClick : function(e){
16121 var item = this.findItemFromChild(e.getTarget());
16123 var index = this.indexOf(item);
16124 if(this.onItemClick(item, index, e) !== false){
16125 this.fireEvent("click", this, index, item, e);
16128 this.clearSelections();
16133 onContextMenu : function(e){
16134 var item = this.findItemFromChild(e.getTarget());
16136 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16141 onDblClick : function(e){
16142 var item = this.findItemFromChild(e.getTarget());
16144 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16148 onItemClick : function(item, index, e)
16150 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16153 if (this.toggleSelect) {
16154 var m = this.isSelected(item) ? 'unselect' : 'select';
16157 _t[m](item, true, false);
16160 if(this.multiSelect || this.singleSelect){
16161 if(this.multiSelect && e.shiftKey && this.lastSelection){
16162 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16164 this.select(item, this.multiSelect && e.ctrlKey);
16165 this.lastSelection = item;
16168 if(!this.tickable){
16169 e.preventDefault();
16177 * Get the number of selected nodes.
16180 getSelectionCount : function(){
16181 return this.selections.length;
16185 * Get the currently selected nodes.
16186 * @return {Array} An array of HTMLElements
16188 getSelectedNodes : function(){
16189 return this.selections;
16193 * Get the indexes of the selected nodes.
16196 getSelectedIndexes : function(){
16197 var indexes = [], s = this.selections;
16198 for(var i = 0, len = s.length; i < len; i++){
16199 indexes.push(s[i].nodeIndex);
16205 * Clear all selections
16206 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16208 clearSelections : function(suppressEvent){
16209 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16210 this.cmp.elements = this.selections;
16211 this.cmp.removeClass(this.selectedClass);
16212 this.selections = [];
16213 if(!suppressEvent){
16214 this.fireEvent("selectionchange", this, this.selections);
16220 * Returns true if the passed node is selected
16221 * @param {HTMLElement/Number} node The node or node index
16222 * @return {Boolean}
16224 isSelected : function(node){
16225 var s = this.selections;
16229 node = this.getNode(node);
16230 return s.indexOf(node) !== -1;
16235 * @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
16236 * @param {Boolean} keepExisting (optional) true to keep existing selections
16237 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16239 select : function(nodeInfo, keepExisting, suppressEvent){
16240 if(nodeInfo instanceof Array){
16242 this.clearSelections(true);
16244 for(var i = 0, len = nodeInfo.length; i < len; i++){
16245 this.select(nodeInfo[i], true, true);
16249 var node = this.getNode(nodeInfo);
16250 if(!node || this.isSelected(node)){
16251 return; // already selected.
16254 this.clearSelections(true);
16257 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16258 Roo.fly(node).addClass(this.selectedClass);
16259 this.selections.push(node);
16260 if(!suppressEvent){
16261 this.fireEvent("selectionchange", this, this.selections);
16269 * @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
16270 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16271 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16273 unselect : function(nodeInfo, keepExisting, suppressEvent)
16275 if(nodeInfo instanceof Array){
16276 Roo.each(this.selections, function(s) {
16277 this.unselect(s, nodeInfo);
16281 var node = this.getNode(nodeInfo);
16282 if(!node || !this.isSelected(node)){
16283 //Roo.log("not selected");
16284 return; // not selected.
16288 Roo.each(this.selections, function(s) {
16290 Roo.fly(node).removeClass(this.selectedClass);
16297 this.selections= ns;
16298 this.fireEvent("selectionchange", this, this.selections);
16302 * Gets a template node.
16303 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16304 * @return {HTMLElement} The node or null if it wasn't found
16306 getNode : function(nodeInfo){
16307 if(typeof nodeInfo == "string"){
16308 return document.getElementById(nodeInfo);
16309 }else if(typeof nodeInfo == "number"){
16310 return this.nodes[nodeInfo];
16316 * Gets a range template nodes.
16317 * @param {Number} startIndex
16318 * @param {Number} endIndex
16319 * @return {Array} An array of nodes
16321 getNodes : function(start, end){
16322 var ns = this.nodes;
16323 start = start || 0;
16324 end = typeof end == "undefined" ? ns.length - 1 : end;
16327 for(var i = start; i <= end; i++){
16331 for(var i = start; i >= end; i--){
16339 * Finds the index of the passed node
16340 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16341 * @return {Number} The index of the node or -1
16343 indexOf : function(node){
16344 node = this.getNode(node);
16345 if(typeof node.nodeIndex == "number"){
16346 return node.nodeIndex;
16348 var ns = this.nodes;
16349 for(var i = 0, len = ns.length; i < len; i++){
16360 * based on jquery fullcalendar
16364 Roo.bootstrap = Roo.bootstrap || {};
16366 * @class Roo.bootstrap.Calendar
16367 * @extends Roo.bootstrap.Component
16368 * Bootstrap Calendar class
16369 * @cfg {Boolean} loadMask (true|false) default false
16370 * @cfg {Object} header generate the user specific header of the calendar, default false
16373 * Create a new Container
16374 * @param {Object} config The config object
16379 Roo.bootstrap.Calendar = function(config){
16380 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16384 * Fires when a date is selected
16385 * @param {DatePicker} this
16386 * @param {Date} date The selected date
16390 * @event monthchange
16391 * Fires when the displayed month changes
16392 * @param {DatePicker} this
16393 * @param {Date} date The selected month
16395 'monthchange': true,
16397 * @event evententer
16398 * Fires when mouse over an event
16399 * @param {Calendar} this
16400 * @param {event} Event
16402 'evententer': true,
16404 * @event eventleave
16405 * Fires when the mouse leaves an
16406 * @param {Calendar} this
16409 'eventleave': true,
16411 * @event eventclick
16412 * Fires when the mouse click an
16413 * @param {Calendar} this
16422 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16425 * @cfg {Number} startDay
16426 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16434 getAutoCreate : function(){
16437 var fc_button = function(name, corner, style, content ) {
16438 return Roo.apply({},{
16440 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16442 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16445 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16456 style : 'width:100%',
16463 cls : 'fc-header-left',
16465 fc_button('prev', 'left', 'arrow', '‹' ),
16466 fc_button('next', 'right', 'arrow', '›' ),
16467 { tag: 'span', cls: 'fc-header-space' },
16468 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16476 cls : 'fc-header-center',
16480 cls: 'fc-header-title',
16483 html : 'month / year'
16491 cls : 'fc-header-right',
16493 /* fc_button('month', 'left', '', 'month' ),
16494 fc_button('week', '', '', 'week' ),
16495 fc_button('day', 'right', '', 'day' )
16507 header = this.header;
16510 var cal_heads = function() {
16512 // fixme - handle this.
16514 for (var i =0; i < Date.dayNames.length; i++) {
16515 var d = Date.dayNames[i];
16518 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16519 html : d.substring(0,3)
16523 ret[0].cls += ' fc-first';
16524 ret[6].cls += ' fc-last';
16527 var cal_cell = function(n) {
16530 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16535 cls: 'fc-day-number',
16539 cls: 'fc-day-content',
16543 style: 'position: relative;' // height: 17px;
16555 var cal_rows = function() {
16558 for (var r = 0; r < 6; r++) {
16565 for (var i =0; i < Date.dayNames.length; i++) {
16566 var d = Date.dayNames[i];
16567 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16570 row.cn[0].cls+=' fc-first';
16571 row.cn[0].cn[0].style = 'min-height:90px';
16572 row.cn[6].cls+=' fc-last';
16576 ret[0].cls += ' fc-first';
16577 ret[4].cls += ' fc-prev-last';
16578 ret[5].cls += ' fc-last';
16585 cls: 'fc-border-separate',
16586 style : 'width:100%',
16594 cls : 'fc-first fc-last',
16612 cls : 'fc-content',
16613 style : "position: relative;",
16616 cls : 'fc-view fc-view-month fc-grid',
16617 style : 'position: relative',
16618 unselectable : 'on',
16621 cls : 'fc-event-container',
16622 style : 'position:absolute;z-index:8;top:0;left:0;'
16640 initEvents : function()
16643 throw "can not find store for calendar";
16649 style: "text-align:center",
16653 style: "background-color:white;width:50%;margin:250 auto",
16657 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16668 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16670 var size = this.el.select('.fc-content', true).first().getSize();
16671 this.maskEl.setSize(size.width, size.height);
16672 this.maskEl.enableDisplayMode("block");
16673 if(!this.loadMask){
16674 this.maskEl.hide();
16677 this.store = Roo.factory(this.store, Roo.data);
16678 this.store.on('load', this.onLoad, this);
16679 this.store.on('beforeload', this.onBeforeLoad, this);
16683 this.cells = this.el.select('.fc-day',true);
16684 //Roo.log(this.cells);
16685 this.textNodes = this.el.query('.fc-day-number');
16686 this.cells.addClassOnOver('fc-state-hover');
16688 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16689 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16690 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16691 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16693 this.on('monthchange', this.onMonthChange, this);
16695 this.update(new Date().clearTime());
16698 resize : function() {
16699 var sz = this.el.getSize();
16701 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16702 this.el.select('.fc-day-content div',true).setHeight(34);
16707 showPrevMonth : function(e){
16708 this.update(this.activeDate.add("mo", -1));
16710 showToday : function(e){
16711 this.update(new Date().clearTime());
16714 showNextMonth : function(e){
16715 this.update(this.activeDate.add("mo", 1));
16719 showPrevYear : function(){
16720 this.update(this.activeDate.add("y", -1));
16724 showNextYear : function(){
16725 this.update(this.activeDate.add("y", 1));
16730 update : function(date)
16732 var vd = this.activeDate;
16733 this.activeDate = date;
16734 // if(vd && this.el){
16735 // var t = date.getTime();
16736 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16737 // Roo.log('using add remove');
16739 // this.fireEvent('monthchange', this, date);
16741 // this.cells.removeClass("fc-state-highlight");
16742 // this.cells.each(function(c){
16743 // if(c.dateValue == t){
16744 // c.addClass("fc-state-highlight");
16745 // setTimeout(function(){
16746 // try{c.dom.firstChild.focus();}catch(e){}
16756 var days = date.getDaysInMonth();
16758 var firstOfMonth = date.getFirstDateOfMonth();
16759 var startingPos = firstOfMonth.getDay()-this.startDay;
16761 if(startingPos < this.startDay){
16765 var pm = date.add(Date.MONTH, -1);
16766 var prevStart = pm.getDaysInMonth()-startingPos;
16768 this.cells = this.el.select('.fc-day',true);
16769 this.textNodes = this.el.query('.fc-day-number');
16770 this.cells.addClassOnOver('fc-state-hover');
16772 var cells = this.cells.elements;
16773 var textEls = this.textNodes;
16775 Roo.each(cells, function(cell){
16776 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16779 days += startingPos;
16781 // convert everything to numbers so it's fast
16782 var day = 86400000;
16783 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16786 //Roo.log(prevStart);
16788 var today = new Date().clearTime().getTime();
16789 var sel = date.clearTime().getTime();
16790 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16791 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16792 var ddMatch = this.disabledDatesRE;
16793 var ddText = this.disabledDatesText;
16794 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16795 var ddaysText = this.disabledDaysText;
16796 var format = this.format;
16798 var setCellClass = function(cal, cell){
16802 //Roo.log('set Cell Class');
16804 var t = d.getTime();
16808 cell.dateValue = t;
16810 cell.className += " fc-today";
16811 cell.className += " fc-state-highlight";
16812 cell.title = cal.todayText;
16815 // disable highlight in other month..
16816 //cell.className += " fc-state-highlight";
16821 cell.className = " fc-state-disabled";
16822 cell.title = cal.minText;
16826 cell.className = " fc-state-disabled";
16827 cell.title = cal.maxText;
16831 if(ddays.indexOf(d.getDay()) != -1){
16832 cell.title = ddaysText;
16833 cell.className = " fc-state-disabled";
16836 if(ddMatch && format){
16837 var fvalue = d.dateFormat(format);
16838 if(ddMatch.test(fvalue)){
16839 cell.title = ddText.replace("%0", fvalue);
16840 cell.className = " fc-state-disabled";
16844 if (!cell.initialClassName) {
16845 cell.initialClassName = cell.dom.className;
16848 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16853 for(; i < startingPos; i++) {
16854 textEls[i].innerHTML = (++prevStart);
16855 d.setDate(d.getDate()+1);
16857 cells[i].className = "fc-past fc-other-month";
16858 setCellClass(this, cells[i]);
16863 for(; i < days; i++){
16864 intDay = i - startingPos + 1;
16865 textEls[i].innerHTML = (intDay);
16866 d.setDate(d.getDate()+1);
16868 cells[i].className = ''; // "x-date-active";
16869 setCellClass(this, cells[i]);
16873 for(; i < 42; i++) {
16874 textEls[i].innerHTML = (++extraDays);
16875 d.setDate(d.getDate()+1);
16877 cells[i].className = "fc-future fc-other-month";
16878 setCellClass(this, cells[i]);
16881 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16883 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16885 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16886 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16888 if(totalRows != 6){
16889 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16890 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16893 this.fireEvent('monthchange', this, date);
16897 if(!this.internalRender){
16898 var main = this.el.dom.firstChild;
16899 var w = main.offsetWidth;
16900 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16901 Roo.fly(main).setWidth(w);
16902 this.internalRender = true;
16903 // opera does not respect the auto grow header center column
16904 // then, after it gets a width opera refuses to recalculate
16905 // without a second pass
16906 if(Roo.isOpera && !this.secondPass){
16907 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16908 this.secondPass = true;
16909 this.update.defer(10, this, [date]);
16916 findCell : function(dt) {
16917 dt = dt.clearTime().getTime();
16919 this.cells.each(function(c){
16920 //Roo.log("check " +c.dateValue + '?=' + dt);
16921 if(c.dateValue == dt){
16931 findCells : function(ev) {
16932 var s = ev.start.clone().clearTime().getTime();
16934 var e= ev.end.clone().clearTime().getTime();
16937 this.cells.each(function(c){
16938 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16940 if(c.dateValue > e){
16943 if(c.dateValue < s){
16952 // findBestRow: function(cells)
16956 // for (var i =0 ; i < cells.length;i++) {
16957 // ret = Math.max(cells[i].rows || 0,ret);
16964 addItem : function(ev)
16966 // look for vertical location slot in
16967 var cells = this.findCells(ev);
16969 // ev.row = this.findBestRow(cells);
16971 // work out the location.
16975 for(var i =0; i < cells.length; i++) {
16977 cells[i].row = cells[0].row;
16980 cells[i].row = cells[i].row + 1;
16990 if (crow.start.getY() == cells[i].getY()) {
16992 crow.end = cells[i];
17009 cells[0].events.push(ev);
17011 this.calevents.push(ev);
17014 clearEvents: function() {
17016 if(!this.calevents){
17020 Roo.each(this.cells.elements, function(c){
17026 Roo.each(this.calevents, function(e) {
17027 Roo.each(e.els, function(el) {
17028 el.un('mouseenter' ,this.onEventEnter, this);
17029 el.un('mouseleave' ,this.onEventLeave, this);
17034 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17040 renderEvents: function()
17044 this.cells.each(function(c) {
17053 if(c.row != c.events.length){
17054 r = 4 - (4 - (c.row - c.events.length));
17057 c.events = ev.slice(0, r);
17058 c.more = ev.slice(r);
17060 if(c.more.length && c.more.length == 1){
17061 c.events.push(c.more.pop());
17064 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17068 this.cells.each(function(c) {
17070 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17073 for (var e = 0; e < c.events.length; e++){
17074 var ev = c.events[e];
17075 var rows = ev.rows;
17077 for(var i = 0; i < rows.length; i++) {
17079 // how many rows should it span..
17082 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17083 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17085 unselectable : "on",
17088 cls: 'fc-event-inner',
17092 // cls: 'fc-event-time',
17093 // html : cells.length > 1 ? '' : ev.time
17097 cls: 'fc-event-title',
17098 html : String.format('{0}', ev.title)
17105 cls: 'ui-resizable-handle ui-resizable-e',
17106 html : '  '
17113 cfg.cls += ' fc-event-start';
17115 if ((i+1) == rows.length) {
17116 cfg.cls += ' fc-event-end';
17119 var ctr = _this.el.select('.fc-event-container',true).first();
17120 var cg = ctr.createChild(cfg);
17122 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17123 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17125 var r = (c.more.length) ? 1 : 0;
17126 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17127 cg.setWidth(ebox.right - sbox.x -2);
17129 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17130 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17131 cg.on('click', _this.onEventClick, _this, ev);
17142 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17143 style : 'position: absolute',
17144 unselectable : "on",
17147 cls: 'fc-event-inner',
17151 cls: 'fc-event-title',
17159 cls: 'ui-resizable-handle ui-resizable-e',
17160 html : '  '
17166 var ctr = _this.el.select('.fc-event-container',true).first();
17167 var cg = ctr.createChild(cfg);
17169 var sbox = c.select('.fc-day-content',true).first().getBox();
17170 var ebox = c.select('.fc-day-content',true).first().getBox();
17172 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17173 cg.setWidth(ebox.right - sbox.x -2);
17175 cg.on('click', _this.onMoreEventClick, _this, c.more);
17185 onEventEnter: function (e, el,event,d) {
17186 this.fireEvent('evententer', this, el, event);
17189 onEventLeave: function (e, el,event,d) {
17190 this.fireEvent('eventleave', this, el, event);
17193 onEventClick: function (e, el,event,d) {
17194 this.fireEvent('eventclick', this, el, event);
17197 onMonthChange: function () {
17201 onMoreEventClick: function(e, el, more)
17205 this.calpopover.placement = 'right';
17206 this.calpopover.setTitle('More');
17208 this.calpopover.setContent('');
17210 var ctr = this.calpopover.el.select('.popover-content', true).first();
17212 Roo.each(more, function(m){
17214 cls : 'fc-event-hori fc-event-draggable',
17217 var cg = ctr.createChild(cfg);
17219 cg.on('click', _this.onEventClick, _this, m);
17222 this.calpopover.show(el);
17227 onLoad: function ()
17229 this.calevents = [];
17232 if(this.store.getCount() > 0){
17233 this.store.data.each(function(d){
17236 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17237 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17238 time : d.data.start_time,
17239 title : d.data.title,
17240 description : d.data.description,
17241 venue : d.data.venue
17246 this.renderEvents();
17248 if(this.calevents.length && this.loadMask){
17249 this.maskEl.hide();
17253 onBeforeLoad: function()
17255 this.clearEvents();
17257 this.maskEl.show();
17271 * @class Roo.bootstrap.Popover
17272 * @extends Roo.bootstrap.Component
17273 * Bootstrap Popover class
17274 * @cfg {String} html contents of the popover (or false to use children..)
17275 * @cfg {String} title of popover (or false to hide)
17276 * @cfg {String} placement how it is placed
17277 * @cfg {String} trigger click || hover (or false to trigger manually)
17278 * @cfg {String} over what (parent or false to trigger manually.)
17279 * @cfg {Number} delay - delay before showing
17282 * Create a new Popover
17283 * @param {Object} config The config object
17286 Roo.bootstrap.Popover = function(config){
17287 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17293 * After the popover show
17295 * @param {Roo.bootstrap.Popover} this
17300 * After the popover hide
17302 * @param {Roo.bootstrap.Popover} this
17308 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17310 title: 'Fill in a title',
17313 placement : 'right',
17314 trigger : 'hover', // hover
17320 can_build_overlaid : false,
17322 getChildContainer : function()
17324 return this.el.select('.popover-content',true).first();
17327 getAutoCreate : function(){
17330 cls : 'popover roo-dynamic',
17331 style: 'display:block',
17337 cls : 'popover-inner',
17341 cls: 'popover-title',
17345 cls : 'popover-content',
17356 setTitle: function(str)
17359 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17361 setContent: function(str)
17364 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17366 // as it get's added to the bottom of the page.
17367 onRender : function(ct, position)
17369 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17371 var cfg = Roo.apply({}, this.getAutoCreate());
17375 cfg.cls += ' ' + this.cls;
17378 cfg.style = this.style;
17380 //Roo.log("adding to ");
17381 this.el = Roo.get(document.body).createChild(cfg, position);
17382 // Roo.log(this.el);
17387 initEvents : function()
17389 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17390 this.el.enableDisplayMode('block');
17392 if (this.over === false) {
17395 if (this.triggers === false) {
17398 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17399 var triggers = this.trigger ? this.trigger.split(' ') : [];
17400 Roo.each(triggers, function(trigger) {
17402 if (trigger == 'click') {
17403 on_el.on('click', this.toggle, this);
17404 } else if (trigger != 'manual') {
17405 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17406 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17408 on_el.on(eventIn ,this.enter, this);
17409 on_el.on(eventOut, this.leave, this);
17420 toggle : function () {
17421 this.hoverState == 'in' ? this.leave() : this.enter();
17424 enter : function () {
17426 clearTimeout(this.timeout);
17428 this.hoverState = 'in';
17430 if (!this.delay || !this.delay.show) {
17435 this.timeout = setTimeout(function () {
17436 if (_t.hoverState == 'in') {
17439 }, this.delay.show)
17442 leave : function() {
17443 clearTimeout(this.timeout);
17445 this.hoverState = 'out';
17447 if (!this.delay || !this.delay.hide) {
17452 this.timeout = setTimeout(function () {
17453 if (_t.hoverState == 'out') {
17456 }, this.delay.hide)
17459 show : function (on_el)
17462 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17466 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17467 if (this.html !== false) {
17468 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17470 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17471 if (!this.title.length) {
17472 this.el.select('.popover-title',true).hide();
17475 var placement = typeof this.placement == 'function' ?
17476 this.placement.call(this, this.el, on_el) :
17479 var autoToken = /\s?auto?\s?/i;
17480 var autoPlace = autoToken.test(placement);
17482 placement = placement.replace(autoToken, '') || 'top';
17486 //this.el.setXY([0,0]);
17488 this.el.dom.style.display='block';
17489 this.el.addClass(placement);
17491 //this.el.appendTo(on_el);
17493 var p = this.getPosition();
17494 var box = this.el.getBox();
17499 var align = Roo.bootstrap.Popover.alignment[placement];
17502 this.el.alignTo(on_el, align[0],align[1]);
17503 //var arrow = this.el.select('.arrow',true).first();
17504 //arrow.set(align[2],
17506 this.el.addClass('in');
17509 if (this.el.hasClass('fade')) {
17513 this.hoverState = 'in';
17515 this.fireEvent('show', this);
17520 this.el.setXY([0,0]);
17521 this.el.removeClass('in');
17523 this.hoverState = null;
17525 this.fireEvent('hide', this);
17530 Roo.bootstrap.Popover.alignment = {
17531 'left' : ['r-l', [-10,0], 'right'],
17532 'right' : ['l-r', [10,0], 'left'],
17533 'bottom' : ['t-b', [0,10], 'top'],
17534 'top' : [ 'b-t', [0,-10], 'bottom']
17545 * @class Roo.bootstrap.Progress
17546 * @extends Roo.bootstrap.Component
17547 * Bootstrap Progress class
17548 * @cfg {Boolean} striped striped of the progress bar
17549 * @cfg {Boolean} active animated of the progress bar
17553 * Create a new Progress
17554 * @param {Object} config The config object
17557 Roo.bootstrap.Progress = function(config){
17558 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17561 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17566 getAutoCreate : function(){
17574 cfg.cls += ' progress-striped';
17578 cfg.cls += ' active';
17597 * @class Roo.bootstrap.ProgressBar
17598 * @extends Roo.bootstrap.Component
17599 * Bootstrap ProgressBar class
17600 * @cfg {Number} aria_valuenow aria-value now
17601 * @cfg {Number} aria_valuemin aria-value min
17602 * @cfg {Number} aria_valuemax aria-value max
17603 * @cfg {String} label label for the progress bar
17604 * @cfg {String} panel (success | info | warning | danger )
17605 * @cfg {String} role role of the progress bar
17606 * @cfg {String} sr_only text
17610 * Create a new ProgressBar
17611 * @param {Object} config The config object
17614 Roo.bootstrap.ProgressBar = function(config){
17615 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17618 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17622 aria_valuemax : 100,
17628 getAutoCreate : function()
17633 cls: 'progress-bar',
17634 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17646 cfg.role = this.role;
17649 if(this.aria_valuenow){
17650 cfg['aria-valuenow'] = this.aria_valuenow;
17653 if(this.aria_valuemin){
17654 cfg['aria-valuemin'] = this.aria_valuemin;
17657 if(this.aria_valuemax){
17658 cfg['aria-valuemax'] = this.aria_valuemax;
17661 if(this.label && !this.sr_only){
17662 cfg.html = this.label;
17666 cfg.cls += ' progress-bar-' + this.panel;
17672 update : function(aria_valuenow)
17674 this.aria_valuenow = aria_valuenow;
17676 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17691 * @class Roo.bootstrap.TabGroup
17692 * @extends Roo.bootstrap.Column
17693 * Bootstrap Column class
17694 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17695 * @cfg {Boolean} carousel true to make the group behave like a carousel
17696 * @cfg {Boolean} bullets show bullets for the panels
17697 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17698 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17699 * @cfg {Boolean} showarrow (true|false) show arrow default true
17702 * Create a new TabGroup
17703 * @param {Object} config The config object
17706 Roo.bootstrap.TabGroup = function(config){
17707 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17709 this.navId = Roo.id();
17712 Roo.bootstrap.TabGroup.register(this);
17716 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17719 transition : false,
17724 slideOnTouch : false,
17727 getAutoCreate : function()
17729 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17731 cfg.cls += ' tab-content';
17733 if (this.carousel) {
17734 cfg.cls += ' carousel slide';
17737 cls : 'carousel-inner',
17741 if(this.bullets && !Roo.isTouch){
17744 cls : 'carousel-bullets',
17748 if(this.bullets_cls){
17749 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17756 cfg.cn[0].cn.push(bullets);
17759 if(this.showarrow){
17760 cfg.cn[0].cn.push({
17762 class : 'carousel-arrow',
17766 class : 'carousel-prev',
17770 class : 'fa fa-chevron-left'
17776 class : 'carousel-next',
17780 class : 'fa fa-chevron-right'
17793 initEvents: function()
17795 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17796 // this.el.on("touchstart", this.onTouchStart, this);
17799 if(this.autoslide){
17802 this.slideFn = window.setInterval(function() {
17803 _this.showPanelNext();
17807 if(this.showarrow){
17808 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17809 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17815 // onTouchStart : function(e, el, o)
17817 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17821 // this.showPanelNext();
17825 getChildContainer : function()
17827 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17831 * register a Navigation item
17832 * @param {Roo.bootstrap.NavItem} the navitem to add
17834 register : function(item)
17836 this.tabs.push( item);
17837 item.navId = this.navId; // not really needed..
17842 getActivePanel : function()
17845 Roo.each(this.tabs, function(t) {
17855 getPanelByName : function(n)
17858 Roo.each(this.tabs, function(t) {
17859 if (t.tabId == n) {
17867 indexOfPanel : function(p)
17870 Roo.each(this.tabs, function(t,i) {
17871 if (t.tabId == p.tabId) {
17880 * show a specific panel
17881 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17882 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17884 showPanel : function (pan)
17886 if(this.transition || typeof(pan) == 'undefined'){
17887 Roo.log("waiting for the transitionend");
17891 if (typeof(pan) == 'number') {
17892 pan = this.tabs[pan];
17895 if (typeof(pan) == 'string') {
17896 pan = this.getPanelByName(pan);
17899 var cur = this.getActivePanel();
17902 Roo.log('pan or acitve pan is undefined');
17906 if (pan.tabId == this.getActivePanel().tabId) {
17910 if (false === cur.fireEvent('beforedeactivate')) {
17914 if(this.bullets > 0 && !Roo.isTouch){
17915 this.setActiveBullet(this.indexOfPanel(pan));
17918 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17920 this.transition = true;
17921 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17922 var lr = dir == 'next' ? 'left' : 'right';
17923 pan.el.addClass(dir); // or prev
17924 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17925 cur.el.addClass(lr); // or right
17926 pan.el.addClass(lr);
17929 cur.el.on('transitionend', function() {
17930 Roo.log("trans end?");
17932 pan.el.removeClass([lr,dir]);
17933 pan.setActive(true);
17935 cur.el.removeClass([lr]);
17936 cur.setActive(false);
17938 _this.transition = false;
17940 }, this, { single: true } );
17945 cur.setActive(false);
17946 pan.setActive(true);
17951 showPanelNext : function()
17953 var i = this.indexOfPanel(this.getActivePanel());
17955 if (i >= this.tabs.length - 1 && !this.autoslide) {
17959 if (i >= this.tabs.length - 1 && this.autoslide) {
17963 this.showPanel(this.tabs[i+1]);
17966 showPanelPrev : function()
17968 var i = this.indexOfPanel(this.getActivePanel());
17970 if (i < 1 && !this.autoslide) {
17974 if (i < 1 && this.autoslide) {
17975 i = this.tabs.length;
17978 this.showPanel(this.tabs[i-1]);
17982 addBullet: function()
17984 if(!this.bullets || Roo.isTouch){
17987 var ctr = this.el.select('.carousel-bullets',true).first();
17988 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
17989 var bullet = ctr.createChild({
17990 cls : 'bullet bullet-' + i
17991 },ctr.dom.lastChild);
17996 bullet.on('click', (function(e, el, o, ii, t){
17998 e.preventDefault();
18000 this.showPanel(ii);
18002 if(this.autoslide && this.slideFn){
18003 clearInterval(this.slideFn);
18004 this.slideFn = window.setInterval(function() {
18005 _this.showPanelNext();
18009 }).createDelegate(this, [i, bullet], true));
18014 setActiveBullet : function(i)
18020 Roo.each(this.el.select('.bullet', true).elements, function(el){
18021 el.removeClass('selected');
18024 var bullet = this.el.select('.bullet-' + i, true).first();
18030 bullet.addClass('selected');
18041 Roo.apply(Roo.bootstrap.TabGroup, {
18045 * register a Navigation Group
18046 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18048 register : function(navgrp)
18050 this.groups[navgrp.navId] = navgrp;
18054 * fetch a Navigation Group based on the navigation ID
18055 * if one does not exist , it will get created.
18056 * @param {string} the navgroup to add
18057 * @returns {Roo.bootstrap.NavGroup} the navgroup
18059 get: function(navId) {
18060 if (typeof(this.groups[navId]) == 'undefined') {
18061 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18063 return this.groups[navId] ;
18078 * @class Roo.bootstrap.TabPanel
18079 * @extends Roo.bootstrap.Component
18080 * Bootstrap TabPanel class
18081 * @cfg {Boolean} active panel active
18082 * @cfg {String} html panel content
18083 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18084 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18085 * @cfg {String} href click to link..
18089 * Create a new TabPanel
18090 * @param {Object} config The config object
18093 Roo.bootstrap.TabPanel = function(config){
18094 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18098 * Fires when the active status changes
18099 * @param {Roo.bootstrap.TabPanel} this
18100 * @param {Boolean} state the new state
18105 * @event beforedeactivate
18106 * Fires before a tab is de-activated - can be used to do validation on a form.
18107 * @param {Roo.bootstrap.TabPanel} this
18108 * @return {Boolean} false if there is an error
18111 'beforedeactivate': true
18114 this.tabId = this.tabId || Roo.id();
18118 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18126 getAutoCreate : function(){
18129 // item is needed for carousel - not sure if it has any effect otherwise
18130 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18131 html: this.html || ''
18135 cfg.cls += ' active';
18139 cfg.tabId = this.tabId;
18146 initEvents: function()
18148 var p = this.parent();
18150 this.navId = this.navId || p.navId;
18152 if (typeof(this.navId) != 'undefined') {
18153 // not really needed.. but just in case.. parent should be a NavGroup.
18154 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18158 var i = tg.tabs.length - 1;
18160 if(this.active && tg.bullets > 0 && i < tg.bullets){
18161 tg.setActiveBullet(i);
18165 this.el.on('click', this.onClick, this);
18168 this.el.on("touchstart", this.onTouchStart, this);
18169 this.el.on("touchmove", this.onTouchMove, this);
18170 this.el.on("touchend", this.onTouchEnd, this);
18175 onRender : function(ct, position)
18177 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18180 setActive : function(state)
18182 Roo.log("panel - set active " + this.tabId + "=" + state);
18184 this.active = state;
18186 this.el.removeClass('active');
18188 } else if (!this.el.hasClass('active')) {
18189 this.el.addClass('active');
18192 this.fireEvent('changed', this, state);
18195 onClick : function(e)
18197 e.preventDefault();
18199 if(!this.href.length){
18203 window.location.href = this.href;
18212 onTouchStart : function(e)
18214 this.swiping = false;
18216 this.startX = e.browserEvent.touches[0].clientX;
18217 this.startY = e.browserEvent.touches[0].clientY;
18220 onTouchMove : function(e)
18222 this.swiping = true;
18224 this.endX = e.browserEvent.touches[0].clientX;
18225 this.endY = e.browserEvent.touches[0].clientY;
18228 onTouchEnd : function(e)
18235 var tabGroup = this.parent();
18237 if(this.endX > this.startX){ // swiping right
18238 tabGroup.showPanelPrev();
18242 if(this.startX > this.endX){ // swiping left
18243 tabGroup.showPanelNext();
18262 * @class Roo.bootstrap.DateField
18263 * @extends Roo.bootstrap.Input
18264 * Bootstrap DateField class
18265 * @cfg {Number} weekStart default 0
18266 * @cfg {String} viewMode default empty, (months|years)
18267 * @cfg {String} minViewMode default empty, (months|years)
18268 * @cfg {Number} startDate default -Infinity
18269 * @cfg {Number} endDate default Infinity
18270 * @cfg {Boolean} todayHighlight default false
18271 * @cfg {Boolean} todayBtn default false
18272 * @cfg {Boolean} calendarWeeks default false
18273 * @cfg {Object} daysOfWeekDisabled default empty
18274 * @cfg {Boolean} singleMode default false (true | false)
18276 * @cfg {Boolean} keyboardNavigation default true
18277 * @cfg {String} language default en
18280 * Create a new DateField
18281 * @param {Object} config The config object
18284 Roo.bootstrap.DateField = function(config){
18285 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18289 * Fires when this field show.
18290 * @param {Roo.bootstrap.DateField} this
18291 * @param {Mixed} date The date value
18296 * Fires when this field hide.
18297 * @param {Roo.bootstrap.DateField} this
18298 * @param {Mixed} date The date value
18303 * Fires when select a date.
18304 * @param {Roo.bootstrap.DateField} this
18305 * @param {Mixed} date The date value
18309 * @event beforeselect
18310 * Fires when before select a date.
18311 * @param {Roo.bootstrap.DateField} this
18312 * @param {Mixed} date The date value
18314 beforeselect : true
18318 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18321 * @cfg {String} format
18322 * The default date format string which can be overriden for localization support. The format must be
18323 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18327 * @cfg {String} altFormats
18328 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18329 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18331 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18339 todayHighlight : false,
18345 keyboardNavigation: true,
18347 calendarWeeks: false,
18349 startDate: -Infinity,
18353 daysOfWeekDisabled: [],
18357 singleMode : false,
18359 UTCDate: function()
18361 return new Date(Date.UTC.apply(Date, arguments));
18364 UTCToday: function()
18366 var today = new Date();
18367 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18370 getDate: function() {
18371 var d = this.getUTCDate();
18372 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18375 getUTCDate: function() {
18379 setDate: function(d) {
18380 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18383 setUTCDate: function(d) {
18385 this.setValue(this.formatDate(this.date));
18388 onRender: function(ct, position)
18391 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18393 this.language = this.language || 'en';
18394 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18395 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18397 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18398 this.format = this.format || 'm/d/y';
18399 this.isInline = false;
18400 this.isInput = true;
18401 this.component = this.el.select('.add-on', true).first() || false;
18402 this.component = (this.component && this.component.length === 0) ? false : this.component;
18403 this.hasInput = this.component && this.inputEl().length;
18405 if (typeof(this.minViewMode === 'string')) {
18406 switch (this.minViewMode) {
18408 this.minViewMode = 1;
18411 this.minViewMode = 2;
18414 this.minViewMode = 0;
18419 if (typeof(this.viewMode === 'string')) {
18420 switch (this.viewMode) {
18433 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18435 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18437 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18439 this.picker().on('mousedown', this.onMousedown, this);
18440 this.picker().on('click', this.onClick, this);
18442 this.picker().addClass('datepicker-dropdown');
18444 this.startViewMode = this.viewMode;
18446 if(this.singleMode){
18447 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18448 v.setVisibilityMode(Roo.Element.DISPLAY);
18452 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18453 v.setStyle('width', '189px');
18457 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18458 if(!this.calendarWeeks){
18463 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18464 v.attr('colspan', function(i, val){
18465 return parseInt(val) + 1;
18470 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18472 this.setStartDate(this.startDate);
18473 this.setEndDate(this.endDate);
18475 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18482 if(this.isInline) {
18487 picker : function()
18489 return this.pickerEl;
18490 // return this.el.select('.datepicker', true).first();
18493 fillDow: function()
18495 var dowCnt = this.weekStart;
18504 if(this.calendarWeeks){
18512 while (dowCnt < this.weekStart + 7) {
18516 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18520 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18523 fillMonths: function()
18526 var months = this.picker().select('>.datepicker-months td', true).first();
18528 months.dom.innerHTML = '';
18534 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18537 months.createChild(month);
18544 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;
18546 if (this.date < this.startDate) {
18547 this.viewDate = new Date(this.startDate);
18548 } else if (this.date > this.endDate) {
18549 this.viewDate = new Date(this.endDate);
18551 this.viewDate = new Date(this.date);
18559 var d = new Date(this.viewDate),
18560 year = d.getUTCFullYear(),
18561 month = d.getUTCMonth(),
18562 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18563 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18564 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18565 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18566 currentDate = this.date && this.date.valueOf(),
18567 today = this.UTCToday();
18569 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18571 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18573 // this.picker.select('>tfoot th.today').
18574 // .text(dates[this.language].today)
18575 // .toggle(this.todayBtn !== false);
18577 this.updateNavArrows();
18580 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18582 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18584 prevMonth.setUTCDate(day);
18586 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18588 var nextMonth = new Date(prevMonth);
18590 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18592 nextMonth = nextMonth.valueOf();
18594 var fillMonths = false;
18596 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18598 while(prevMonth.valueOf() < nextMonth) {
18601 if (prevMonth.getUTCDay() === this.weekStart) {
18603 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18611 if(this.calendarWeeks){
18612 // ISO 8601: First week contains first thursday.
18613 // ISO also states week starts on Monday, but we can be more abstract here.
18615 // Start of current week: based on weekstart/current date
18616 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18617 // Thursday of this week
18618 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18619 // First Thursday of year, year from thursday
18620 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18621 // Calendar week: ms between thursdays, div ms per day, div 7 days
18622 calWeek = (th - yth) / 864e5 / 7 + 1;
18624 fillMonths.cn.push({
18632 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18634 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18637 if (this.todayHighlight &&
18638 prevMonth.getUTCFullYear() == today.getFullYear() &&
18639 prevMonth.getUTCMonth() == today.getMonth() &&
18640 prevMonth.getUTCDate() == today.getDate()) {
18641 clsName += ' today';
18644 if (currentDate && prevMonth.valueOf() === currentDate) {
18645 clsName += ' active';
18648 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18649 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18650 clsName += ' disabled';
18653 fillMonths.cn.push({
18655 cls: 'day ' + clsName,
18656 html: prevMonth.getDate()
18659 prevMonth.setDate(prevMonth.getDate()+1);
18662 var currentYear = this.date && this.date.getUTCFullYear();
18663 var currentMonth = this.date && this.date.getUTCMonth();
18665 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18667 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18668 v.removeClass('active');
18670 if(currentYear === year && k === currentMonth){
18671 v.addClass('active');
18674 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18675 v.addClass('disabled');
18681 year = parseInt(year/10, 10) * 10;
18683 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18685 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18688 for (var i = -1; i < 11; i++) {
18689 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18691 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18699 showMode: function(dir)
18702 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18705 Roo.each(this.picker().select('>div',true).elements, function(v){
18706 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18709 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18714 if(this.isInline) {
18718 this.picker().removeClass(['bottom', 'top']);
18720 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18722 * place to the top of element!
18726 this.picker().addClass('top');
18727 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18732 this.picker().addClass('bottom');
18734 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18737 parseDate : function(value)
18739 if(!value || value instanceof Date){
18742 var v = Date.parseDate(value, this.format);
18743 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18744 v = Date.parseDate(value, 'Y-m-d');
18746 if(!v && this.altFormats){
18747 if(!this.altFormatsArray){
18748 this.altFormatsArray = this.altFormats.split("|");
18750 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18751 v = Date.parseDate(value, this.altFormatsArray[i]);
18757 formatDate : function(date, fmt)
18759 return (!date || !(date instanceof Date)) ?
18760 date : date.dateFormat(fmt || this.format);
18763 onFocus : function()
18765 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18769 onBlur : function()
18771 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18773 var d = this.inputEl().getValue();
18782 this.picker().show();
18786 this.fireEvent('show', this, this.date);
18791 if(this.isInline) {
18794 this.picker().hide();
18795 this.viewMode = this.startViewMode;
18798 this.fireEvent('hide', this, this.date);
18802 onMousedown: function(e)
18804 e.stopPropagation();
18805 e.preventDefault();
18810 Roo.bootstrap.DateField.superclass.keyup.call(this);
18814 setValue: function(v)
18816 if(this.fireEvent('beforeselect', this, v) !== false){
18817 var d = new Date(this.parseDate(v) ).clearTime();
18819 if(isNaN(d.getTime())){
18820 this.date = this.viewDate = '';
18821 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18825 v = this.formatDate(d);
18827 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18829 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18833 this.fireEvent('select', this, this.date);
18837 getValue: function()
18839 return this.formatDate(this.date);
18842 fireKey: function(e)
18844 if (!this.picker().isVisible()){
18845 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18851 var dateChanged = false,
18853 newDate, newViewDate;
18858 e.preventDefault();
18862 if (!this.keyboardNavigation) {
18865 dir = e.keyCode == 37 ? -1 : 1;
18868 newDate = this.moveYear(this.date, dir);
18869 newViewDate = this.moveYear(this.viewDate, dir);
18870 } else if (e.shiftKey){
18871 newDate = this.moveMonth(this.date, dir);
18872 newViewDate = this.moveMonth(this.viewDate, dir);
18874 newDate = new Date(this.date);
18875 newDate.setUTCDate(this.date.getUTCDate() + dir);
18876 newViewDate = new Date(this.viewDate);
18877 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18879 if (this.dateWithinRange(newDate)){
18880 this.date = newDate;
18881 this.viewDate = newViewDate;
18882 this.setValue(this.formatDate(this.date));
18884 e.preventDefault();
18885 dateChanged = true;
18890 if (!this.keyboardNavigation) {
18893 dir = e.keyCode == 38 ? -1 : 1;
18895 newDate = this.moveYear(this.date, dir);
18896 newViewDate = this.moveYear(this.viewDate, dir);
18897 } else if (e.shiftKey){
18898 newDate = this.moveMonth(this.date, dir);
18899 newViewDate = this.moveMonth(this.viewDate, dir);
18901 newDate = new Date(this.date);
18902 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18903 newViewDate = new Date(this.viewDate);
18904 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18906 if (this.dateWithinRange(newDate)){
18907 this.date = newDate;
18908 this.viewDate = newViewDate;
18909 this.setValue(this.formatDate(this.date));
18911 e.preventDefault();
18912 dateChanged = true;
18916 this.setValue(this.formatDate(this.date));
18918 e.preventDefault();
18921 this.setValue(this.formatDate(this.date));
18935 onClick: function(e)
18937 e.stopPropagation();
18938 e.preventDefault();
18940 var target = e.getTarget();
18942 if(target.nodeName.toLowerCase() === 'i'){
18943 target = Roo.get(target).dom.parentNode;
18946 var nodeName = target.nodeName;
18947 var className = target.className;
18948 var html = target.innerHTML;
18949 //Roo.log(nodeName);
18951 switch(nodeName.toLowerCase()) {
18953 switch(className) {
18959 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18960 switch(this.viewMode){
18962 this.viewDate = this.moveMonth(this.viewDate, dir);
18966 this.viewDate = this.moveYear(this.viewDate, dir);
18972 var date = new Date();
18973 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18975 this.setValue(this.formatDate(this.date));
18982 if (className.indexOf('disabled') < 0) {
18983 this.viewDate.setUTCDate(1);
18984 if (className.indexOf('month') > -1) {
18985 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18987 var year = parseInt(html, 10) || 0;
18988 this.viewDate.setUTCFullYear(year);
18992 if(this.singleMode){
18993 this.setValue(this.formatDate(this.viewDate));
19004 //Roo.log(className);
19005 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19006 var day = parseInt(html, 10) || 1;
19007 var year = this.viewDate.getUTCFullYear(),
19008 month = this.viewDate.getUTCMonth();
19010 if (className.indexOf('old') > -1) {
19017 } else if (className.indexOf('new') > -1) {
19025 //Roo.log([year,month,day]);
19026 this.date = this.UTCDate(year, month, day,0,0,0,0);
19027 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19029 //Roo.log(this.formatDate(this.date));
19030 this.setValue(this.formatDate(this.date));
19037 setStartDate: function(startDate)
19039 this.startDate = startDate || -Infinity;
19040 if (this.startDate !== -Infinity) {
19041 this.startDate = this.parseDate(this.startDate);
19044 this.updateNavArrows();
19047 setEndDate: function(endDate)
19049 this.endDate = endDate || Infinity;
19050 if (this.endDate !== Infinity) {
19051 this.endDate = this.parseDate(this.endDate);
19054 this.updateNavArrows();
19057 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19059 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19060 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19061 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19063 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19064 return parseInt(d, 10);
19067 this.updateNavArrows();
19070 updateNavArrows: function()
19072 if(this.singleMode){
19076 var d = new Date(this.viewDate),
19077 year = d.getUTCFullYear(),
19078 month = d.getUTCMonth();
19080 Roo.each(this.picker().select('.prev', true).elements, function(v){
19082 switch (this.viewMode) {
19085 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19091 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19098 Roo.each(this.picker().select('.next', true).elements, function(v){
19100 switch (this.viewMode) {
19103 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19109 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19117 moveMonth: function(date, dir)
19122 var new_date = new Date(date.valueOf()),
19123 day = new_date.getUTCDate(),
19124 month = new_date.getUTCMonth(),
19125 mag = Math.abs(dir),
19127 dir = dir > 0 ? 1 : -1;
19130 // If going back one month, make sure month is not current month
19131 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19133 return new_date.getUTCMonth() == month;
19135 // If going forward one month, make sure month is as expected
19136 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19138 return new_date.getUTCMonth() != new_month;
19140 new_month = month + dir;
19141 new_date.setUTCMonth(new_month);
19142 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19143 if (new_month < 0 || new_month > 11) {
19144 new_month = (new_month + 12) % 12;
19147 // For magnitudes >1, move one month at a time...
19148 for (var i=0; i<mag; i++) {
19149 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19150 new_date = this.moveMonth(new_date, dir);
19152 // ...then reset the day, keeping it in the new month
19153 new_month = new_date.getUTCMonth();
19154 new_date.setUTCDate(day);
19156 return new_month != new_date.getUTCMonth();
19159 // Common date-resetting loop -- if date is beyond end of month, make it
19162 new_date.setUTCDate(--day);
19163 new_date.setUTCMonth(new_month);
19168 moveYear: function(date, dir)
19170 return this.moveMonth(date, dir*12);
19173 dateWithinRange: function(date)
19175 return date >= this.startDate && date <= this.endDate;
19181 this.picker().remove();
19184 validateValue : function(value)
19186 if(this.getEl().hasClass('hidden')){
19190 if(value.length < 1) {
19191 if(this.allowBlank){
19197 if(value.length < this.minLength){
19200 if(value.length > this.maxLength){
19204 var vt = Roo.form.VTypes;
19205 if(!vt[this.vtype](value, this)){
19209 if(typeof this.validator == "function"){
19210 var msg = this.validator(value);
19216 if(this.regex && !this.regex.test(value)){
19220 if(typeof(this.parseDate(value)) == 'undefined'){
19224 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19228 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19236 setVisible : function(visible)
19242 this.getEl().removeClass('hidden');
19248 this.getEl().addClass('hidden');
19253 Roo.apply(Roo.bootstrap.DateField, {
19264 html: '<i class="fa fa-arrow-left"/>'
19274 html: '<i class="fa fa-arrow-right"/>'
19316 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19317 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19318 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19319 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19320 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19333 navFnc: 'FullYear',
19338 navFnc: 'FullYear',
19343 Roo.apply(Roo.bootstrap.DateField, {
19347 cls: 'datepicker dropdown-menu roo-dynamic',
19351 cls: 'datepicker-days',
19355 cls: 'table-condensed',
19357 Roo.bootstrap.DateField.head,
19361 Roo.bootstrap.DateField.footer
19368 cls: 'datepicker-months',
19372 cls: 'table-condensed',
19374 Roo.bootstrap.DateField.head,
19375 Roo.bootstrap.DateField.content,
19376 Roo.bootstrap.DateField.footer
19383 cls: 'datepicker-years',
19387 cls: 'table-condensed',
19389 Roo.bootstrap.DateField.head,
19390 Roo.bootstrap.DateField.content,
19391 Roo.bootstrap.DateField.footer
19410 * @class Roo.bootstrap.TimeField
19411 * @extends Roo.bootstrap.Input
19412 * Bootstrap DateField class
19416 * Create a new TimeField
19417 * @param {Object} config The config object
19420 Roo.bootstrap.TimeField = function(config){
19421 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19425 * Fires when this field show.
19426 * @param {Roo.bootstrap.DateField} thisthis
19427 * @param {Mixed} date The date value
19432 * Fires when this field hide.
19433 * @param {Roo.bootstrap.DateField} this
19434 * @param {Mixed} date The date value
19439 * Fires when select a date.
19440 * @param {Roo.bootstrap.DateField} this
19441 * @param {Mixed} date The date value
19447 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19450 * @cfg {String} format
19451 * The default time format string which can be overriden for localization support. The format must be
19452 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19456 onRender: function(ct, position)
19459 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19461 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19463 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19465 this.pop = this.picker().select('>.datepicker-time',true).first();
19466 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19468 this.picker().on('mousedown', this.onMousedown, this);
19469 this.picker().on('click', this.onClick, this);
19471 this.picker().addClass('datepicker-dropdown');
19476 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19477 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19478 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19479 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19480 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19481 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19485 fireKey: function(e){
19486 if (!this.picker().isVisible()){
19487 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19493 e.preventDefault();
19501 this.onTogglePeriod();
19504 this.onIncrementMinutes();
19507 this.onDecrementMinutes();
19516 onClick: function(e) {
19517 e.stopPropagation();
19518 e.preventDefault();
19521 picker : function()
19523 return this.el.select('.datepicker', true).first();
19526 fillTime: function()
19528 var time = this.pop.select('tbody', true).first();
19530 time.dom.innerHTML = '';
19545 cls: 'hours-up glyphicon glyphicon-chevron-up'
19565 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19586 cls: 'timepicker-hour',
19601 cls: 'timepicker-minute',
19616 cls: 'btn btn-primary period',
19638 cls: 'hours-down glyphicon glyphicon-chevron-down'
19658 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19676 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19683 var hours = this.time.getHours();
19684 var minutes = this.time.getMinutes();
19697 hours = hours - 12;
19701 hours = '0' + hours;
19705 minutes = '0' + minutes;
19708 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19709 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19710 this.pop.select('button', true).first().dom.innerHTML = period;
19716 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19718 var cls = ['bottom'];
19720 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19727 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19732 this.picker().addClass(cls.join('-'));
19736 Roo.each(cls, function(c){
19738 _this.picker().setTop(_this.inputEl().getHeight());
19742 _this.picker().setTop(0 - _this.picker().getHeight());
19747 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19751 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19758 onFocus : function()
19760 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19764 onBlur : function()
19766 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19772 this.picker().show();
19777 this.fireEvent('show', this, this.date);
19782 this.picker().hide();
19785 this.fireEvent('hide', this, this.date);
19788 setTime : function()
19791 this.setValue(this.time.format(this.format));
19793 this.fireEvent('select', this, this.date);
19798 onMousedown: function(e){
19799 e.stopPropagation();
19800 e.preventDefault();
19803 onIncrementHours: function()
19805 Roo.log('onIncrementHours');
19806 this.time = this.time.add(Date.HOUR, 1);
19811 onDecrementHours: function()
19813 Roo.log('onDecrementHours');
19814 this.time = this.time.add(Date.HOUR, -1);
19818 onIncrementMinutes: function()
19820 Roo.log('onIncrementMinutes');
19821 this.time = this.time.add(Date.MINUTE, 1);
19825 onDecrementMinutes: function()
19827 Roo.log('onDecrementMinutes');
19828 this.time = this.time.add(Date.MINUTE, -1);
19832 onTogglePeriod: function()
19834 Roo.log('onTogglePeriod');
19835 this.time = this.time.add(Date.HOUR, 12);
19842 Roo.apply(Roo.bootstrap.TimeField, {
19872 cls: 'btn btn-info ok',
19884 Roo.apply(Roo.bootstrap.TimeField, {
19888 cls: 'datepicker dropdown-menu',
19892 cls: 'datepicker-time',
19896 cls: 'table-condensed',
19898 Roo.bootstrap.TimeField.content,
19899 Roo.bootstrap.TimeField.footer
19918 * @class Roo.bootstrap.MonthField
19919 * @extends Roo.bootstrap.Input
19920 * Bootstrap MonthField class
19922 * @cfg {String} language default en
19925 * Create a new MonthField
19926 * @param {Object} config The config object
19929 Roo.bootstrap.MonthField = function(config){
19930 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19935 * Fires when this field show.
19936 * @param {Roo.bootstrap.MonthField} this
19937 * @param {Mixed} date The date value
19942 * Fires when this field hide.
19943 * @param {Roo.bootstrap.MonthField} this
19944 * @param {Mixed} date The date value
19949 * Fires when select a date.
19950 * @param {Roo.bootstrap.MonthField} this
19951 * @param {String} oldvalue The old value
19952 * @param {String} newvalue The new value
19958 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19960 onRender: function(ct, position)
19963 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19965 this.language = this.language || 'en';
19966 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19967 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19969 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19970 this.isInline = false;
19971 this.isInput = true;
19972 this.component = this.el.select('.add-on', true).first() || false;
19973 this.component = (this.component && this.component.length === 0) ? false : this.component;
19974 this.hasInput = this.component && this.inputEL().length;
19976 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19978 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19980 this.picker().on('mousedown', this.onMousedown, this);
19981 this.picker().on('click', this.onClick, this);
19983 this.picker().addClass('datepicker-dropdown');
19985 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19986 v.setStyle('width', '189px');
19993 if(this.isInline) {
19999 setValue: function(v, suppressEvent)
20001 var o = this.getValue();
20003 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20007 if(suppressEvent !== true){
20008 this.fireEvent('select', this, o, v);
20013 getValue: function()
20018 onClick: function(e)
20020 e.stopPropagation();
20021 e.preventDefault();
20023 var target = e.getTarget();
20025 if(target.nodeName.toLowerCase() === 'i'){
20026 target = Roo.get(target).dom.parentNode;
20029 var nodeName = target.nodeName;
20030 var className = target.className;
20031 var html = target.innerHTML;
20033 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20037 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20039 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20045 picker : function()
20047 return this.pickerEl;
20050 fillMonths: function()
20053 var months = this.picker().select('>.datepicker-months td', true).first();
20055 months.dom.innerHTML = '';
20061 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20064 months.createChild(month);
20073 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20074 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20077 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20078 e.removeClass('active');
20080 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20081 e.addClass('active');
20088 if(this.isInline) {
20092 this.picker().removeClass(['bottom', 'top']);
20094 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20096 * place to the top of element!
20100 this.picker().addClass('top');
20101 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20106 this.picker().addClass('bottom');
20108 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20111 onFocus : function()
20113 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20117 onBlur : function()
20119 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20121 var d = this.inputEl().getValue();
20130 this.picker().show();
20131 this.picker().select('>.datepicker-months', true).first().show();
20135 this.fireEvent('show', this, this.date);
20140 if(this.isInline) {
20143 this.picker().hide();
20144 this.fireEvent('hide', this, this.date);
20148 onMousedown: function(e)
20150 e.stopPropagation();
20151 e.preventDefault();
20156 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20160 fireKey: function(e)
20162 if (!this.picker().isVisible()){
20163 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20174 e.preventDefault();
20178 dir = e.keyCode == 37 ? -1 : 1;
20180 this.vIndex = this.vIndex + dir;
20182 if(this.vIndex < 0){
20186 if(this.vIndex > 11){
20190 if(isNaN(this.vIndex)){
20194 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20200 dir = e.keyCode == 38 ? -1 : 1;
20202 this.vIndex = this.vIndex + dir * 4;
20204 if(this.vIndex < 0){
20208 if(this.vIndex > 11){
20212 if(isNaN(this.vIndex)){
20216 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20221 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20222 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20226 e.preventDefault();
20229 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20230 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20246 this.picker().remove();
20251 Roo.apply(Roo.bootstrap.MonthField, {
20270 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20271 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20276 Roo.apply(Roo.bootstrap.MonthField, {
20280 cls: 'datepicker dropdown-menu roo-dynamic',
20284 cls: 'datepicker-months',
20288 cls: 'table-condensed',
20290 Roo.bootstrap.DateField.content
20310 * @class Roo.bootstrap.CheckBox
20311 * @extends Roo.bootstrap.Input
20312 * Bootstrap CheckBox class
20314 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20315 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20316 * @cfg {String} boxLabel The text that appears beside the checkbox
20317 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20318 * @cfg {Boolean} checked initnal the element
20319 * @cfg {Boolean} inline inline the element (default false)
20320 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20321 * @cfg {String} tooltip label tooltip
20324 * Create a new CheckBox
20325 * @param {Object} config The config object
20328 Roo.bootstrap.CheckBox = function(config){
20329 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20334 * Fires when the element is checked or unchecked.
20335 * @param {Roo.bootstrap.CheckBox} this This input
20336 * @param {Boolean} checked The new checked value
20341 * Fires when the element is click.
20342 * @param {Roo.bootstrap.CheckBox} this This input
20349 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20351 inputType: 'checkbox',
20360 getAutoCreate : function()
20362 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20368 cfg.cls = 'form-group ' + this.inputType; //input-group
20371 cfg.cls += ' ' + this.inputType + '-inline';
20377 type : this.inputType,
20378 value : this.inputValue,
20379 cls : 'roo-' + this.inputType, //'form-box',
20380 placeholder : this.placeholder || ''
20384 if(this.inputType != 'radio'){
20388 cls : 'roo-hidden-value',
20389 value : this.checked ? this.inputValue : this.valueOff
20394 if (this.weight) { // Validity check?
20395 cfg.cls += " " + this.inputType + "-" + this.weight;
20398 if (this.disabled) {
20399 input.disabled=true;
20403 input.checked = this.checked;
20408 input.name = this.name;
20410 if(this.inputType != 'radio'){
20411 hidden.name = this.name;
20412 input.name = '_hidden_' + this.name;
20417 input.cls += ' input-' + this.size;
20422 ['xs','sm','md','lg'].map(function(size){
20423 if (settings[size]) {
20424 cfg.cls += ' col-' + size + '-' + settings[size];
20428 var inputblock = input;
20430 if (this.before || this.after) {
20433 cls : 'input-group',
20438 inputblock.cn.push({
20440 cls : 'input-group-addon',
20445 inputblock.cn.push(input);
20447 if(this.inputType != 'radio'){
20448 inputblock.cn.push(hidden);
20452 inputblock.cn.push({
20454 cls : 'input-group-addon',
20461 if (align ==='left' && this.fieldLabel.length) {
20462 // Roo.log("left and has label");
20467 cls : 'control-label',
20468 html : this.fieldLabel
20478 if(this.labelWidth > 12){
20479 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20482 if(this.labelWidth < 13 && this.labelmd == 0){
20483 this.labelmd = this.labelWidth;
20486 if(this.labellg > 0){
20487 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20488 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20491 if(this.labelmd > 0){
20492 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20493 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20496 if(this.labelsm > 0){
20497 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20498 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20501 if(this.labelxs > 0){
20502 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20503 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20506 } else if ( this.fieldLabel.length) {
20507 // Roo.log(" label");
20511 tag: this.boxLabel ? 'span' : 'label',
20513 cls: 'control-label box-input-label',
20514 //cls : 'input-group-addon',
20515 html : this.fieldLabel
20524 // Roo.log(" no label && no align");
20525 cfg.cn = [ inputblock ] ;
20531 var boxLabelCfg = {
20533 //'for': id, // box label is handled by onclick - so no for...
20535 html: this.boxLabel
20539 boxLabelCfg.tooltip = this.tooltip;
20542 cfg.cn.push(boxLabelCfg);
20545 if(this.inputType != 'radio'){
20546 cfg.cn.push(hidden);
20554 * return the real input element.
20556 inputEl: function ()
20558 return this.el.select('input.roo-' + this.inputType,true).first();
20560 hiddenEl: function ()
20562 return this.el.select('input.roo-hidden-value',true).first();
20565 labelEl: function()
20567 return this.el.select('label.control-label',true).first();
20569 /* depricated... */
20573 return this.labelEl();
20576 boxLabelEl: function()
20578 return this.el.select('label.box-label',true).first();
20581 initEvents : function()
20583 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20585 this.inputEl().on('click', this.onClick, this);
20587 if (this.boxLabel) {
20588 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20591 this.startValue = this.getValue();
20594 Roo.bootstrap.CheckBox.register(this);
20598 onClick : function(e)
20600 if(this.fireEvent('click', this, e) !== false){
20601 this.setChecked(!this.checked);
20606 setChecked : function(state,suppressEvent)
20608 this.startValue = this.getValue();
20610 if(this.inputType == 'radio'){
20612 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20613 e.dom.checked = false;
20616 this.inputEl().dom.checked = true;
20618 this.inputEl().dom.value = this.inputValue;
20620 if(suppressEvent !== true){
20621 this.fireEvent('check', this, true);
20629 this.checked = state;
20631 this.inputEl().dom.checked = state;
20634 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20636 if(suppressEvent !== true){
20637 this.fireEvent('check', this, state);
20643 getValue : function()
20645 if(this.inputType == 'radio'){
20646 return this.getGroupValue();
20649 return this.hiddenEl().dom.value;
20653 getGroupValue : function()
20655 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20659 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20662 setValue : function(v,suppressEvent)
20664 if(this.inputType == 'radio'){
20665 this.setGroupValue(v, suppressEvent);
20669 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20674 setGroupValue : function(v, suppressEvent)
20676 this.startValue = this.getValue();
20678 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20679 e.dom.checked = false;
20681 if(e.dom.value == v){
20682 e.dom.checked = true;
20686 if(suppressEvent !== true){
20687 this.fireEvent('check', this, true);
20695 validate : function()
20697 if(this.getEl().hasClass('hidden')){
20703 (this.inputType == 'radio' && this.validateRadio()) ||
20704 (this.inputType == 'checkbox' && this.validateCheckbox())
20710 this.markInvalid();
20714 validateRadio : function()
20716 if(this.getEl().hasClass('hidden')){
20720 if(this.allowBlank){
20726 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20727 if(!e.dom.checked){
20739 validateCheckbox : function()
20742 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20743 //return (this.getValue() == this.inputValue) ? true : false;
20746 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20754 for(var i in group){
20755 if(group[i].el.isVisible(true)){
20763 for(var i in group){
20768 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20775 * Mark this field as valid
20777 markValid : function()
20781 this.fireEvent('valid', this);
20783 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20786 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20793 if(this.inputType == 'radio'){
20794 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20795 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20796 e.findParent('.form-group', false, true).addClass(_this.validClass);
20803 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20804 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20808 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20814 for(var i in group){
20815 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20816 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20821 * Mark this field as invalid
20822 * @param {String} msg The validation message
20824 markInvalid : function(msg)
20826 if(this.allowBlank){
20832 this.fireEvent('invalid', this, msg);
20834 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20837 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20841 label.markInvalid();
20844 if(this.inputType == 'radio'){
20845 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20846 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20847 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20854 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20855 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20859 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20865 for(var i in group){
20866 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20867 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20872 clearInvalid : function()
20874 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20876 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20878 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20880 if (label && label.iconEl) {
20881 label.iconEl.removeClass(label.validClass);
20882 label.iconEl.removeClass(label.invalidClass);
20886 disable : function()
20888 if(this.inputType != 'radio'){
20889 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20896 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20897 _this.getActionEl().addClass(this.disabledClass);
20898 e.dom.disabled = true;
20902 this.disabled = true;
20903 this.fireEvent("disable", this);
20907 enable : function()
20909 if(this.inputType != 'radio'){
20910 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20917 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20918 _this.getActionEl().removeClass(this.disabledClass);
20919 e.dom.disabled = false;
20923 this.disabled = false;
20924 this.fireEvent("enable", this);
20928 setBoxLabel : function(v)
20933 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20939 Roo.apply(Roo.bootstrap.CheckBox, {
20944 * register a CheckBox Group
20945 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20947 register : function(checkbox)
20949 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20950 this.groups[checkbox.groupId] = {};
20953 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20957 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20961 * fetch a CheckBox Group based on the group ID
20962 * @param {string} the group ID
20963 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20965 get: function(groupId) {
20966 if (typeof(this.groups[groupId]) == 'undefined') {
20970 return this.groups[groupId] ;
20983 * @class Roo.bootstrap.Radio
20984 * @extends Roo.bootstrap.Component
20985 * Bootstrap Radio class
20986 * @cfg {String} boxLabel - the label associated
20987 * @cfg {String} value - the value of radio
20990 * Create a new Radio
20991 * @param {Object} config The config object
20993 Roo.bootstrap.Radio = function(config){
20994 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
20998 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21004 getAutoCreate : function()
21008 cls : 'form-group radio',
21013 html : this.boxLabel
21021 initEvents : function()
21023 this.parent().register(this);
21025 this.el.on('click', this.onClick, this);
21029 onClick : function(e)
21031 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21032 this.setChecked(true);
21036 setChecked : function(state, suppressEvent)
21038 this.parent().setValue(this.value, suppressEvent);
21042 setBoxLabel : function(v)
21047 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21062 * @class Roo.bootstrap.SecurePass
21063 * @extends Roo.bootstrap.Input
21064 * Bootstrap SecurePass class
21068 * Create a new SecurePass
21069 * @param {Object} config The config object
21072 Roo.bootstrap.SecurePass = function (config) {
21073 // these go here, so the translation tool can replace them..
21075 PwdEmpty: "Please type a password, and then retype it to confirm.",
21076 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21077 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21078 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21079 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21080 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21081 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21082 TooWeak: "Your password is Too Weak."
21084 this.meterLabel = "Password strength:";
21085 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21086 this.meterClass = [
21087 "roo-password-meter-tooweak",
21088 "roo-password-meter-weak",
21089 "roo-password-meter-medium",
21090 "roo-password-meter-strong",
21091 "roo-password-meter-grey"
21096 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21099 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21101 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21103 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21104 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21105 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21106 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21107 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21108 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21109 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21119 * @cfg {String/Object} Label for the strength meter (defaults to
21120 * 'Password strength:')
21125 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21126 * ['Weak', 'Medium', 'Strong'])
21129 pwdStrengths: false,
21142 initEvents: function ()
21144 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21146 if (this.el.is('input[type=password]') && Roo.isSafari) {
21147 this.el.on('keydown', this.SafariOnKeyDown, this);
21150 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21153 onRender: function (ct, position)
21155 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21156 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21157 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21159 this.trigger.createChild({
21164 cls: 'roo-password-meter-grey col-xs-12',
21167 //width: this.meterWidth + 'px'
21171 cls: 'roo-password-meter-text'
21177 if (this.hideTrigger) {
21178 this.trigger.setDisplayed(false);
21180 this.setSize(this.width || '', this.height || '');
21183 onDestroy: function ()
21185 if (this.trigger) {
21186 this.trigger.removeAllListeners();
21187 this.trigger.remove();
21190 this.wrap.remove();
21192 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21195 checkStrength: function ()
21197 var pwd = this.inputEl().getValue();
21198 if (pwd == this._lastPwd) {
21203 if (this.ClientSideStrongPassword(pwd)) {
21205 } else if (this.ClientSideMediumPassword(pwd)) {
21207 } else if (this.ClientSideWeakPassword(pwd)) {
21213 Roo.log('strength1: ' + strength);
21215 //var pm = this.trigger.child('div/div/div').dom;
21216 var pm = this.trigger.child('div/div');
21217 pm.removeClass(this.meterClass);
21218 pm.addClass(this.meterClass[strength]);
21221 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21223 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21225 this._lastPwd = pwd;
21229 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21231 this._lastPwd = '';
21233 var pm = this.trigger.child('div/div');
21234 pm.removeClass(this.meterClass);
21235 pm.addClass('roo-password-meter-grey');
21238 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21241 this.inputEl().dom.type='password';
21244 validateValue: function (value)
21247 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21250 if (value.length == 0) {
21251 if (this.allowBlank) {
21252 this.clearInvalid();
21256 this.markInvalid(this.errors.PwdEmpty);
21257 this.errorMsg = this.errors.PwdEmpty;
21265 if ('[\x21-\x7e]*'.match(value)) {
21266 this.markInvalid(this.errors.PwdBadChar);
21267 this.errorMsg = this.errors.PwdBadChar;
21270 if (value.length < 6) {
21271 this.markInvalid(this.errors.PwdShort);
21272 this.errorMsg = this.errors.PwdShort;
21275 if (value.length > 16) {
21276 this.markInvalid(this.errors.PwdLong);
21277 this.errorMsg = this.errors.PwdLong;
21281 if (this.ClientSideStrongPassword(value)) {
21283 } else if (this.ClientSideMediumPassword(value)) {
21285 } else if (this.ClientSideWeakPassword(value)) {
21292 if (strength < 2) {
21293 //this.markInvalid(this.errors.TooWeak);
21294 this.errorMsg = this.errors.TooWeak;
21299 console.log('strength2: ' + strength);
21301 //var pm = this.trigger.child('div/div/div').dom;
21303 var pm = this.trigger.child('div/div');
21304 pm.removeClass(this.meterClass);
21305 pm.addClass(this.meterClass[strength]);
21307 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21309 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21311 this.errorMsg = '';
21315 CharacterSetChecks: function (type)
21318 this.fResult = false;
21321 isctype: function (character, type)
21324 case this.kCapitalLetter:
21325 if (character >= 'A' && character <= 'Z') {
21330 case this.kSmallLetter:
21331 if (character >= 'a' && character <= 'z') {
21337 if (character >= '0' && character <= '9') {
21342 case this.kPunctuation:
21343 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21354 IsLongEnough: function (pwd, size)
21356 return !(pwd == null || isNaN(size) || pwd.length < size);
21359 SpansEnoughCharacterSets: function (word, nb)
21361 if (!this.IsLongEnough(word, nb))
21366 var characterSetChecks = new Array(
21367 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21368 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21371 for (var index = 0; index < word.length; ++index) {
21372 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21373 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21374 characterSetChecks[nCharSet].fResult = true;
21381 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21382 if (characterSetChecks[nCharSet].fResult) {
21387 if (nCharSets < nb) {
21393 ClientSideStrongPassword: function (pwd)
21395 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21398 ClientSideMediumPassword: function (pwd)
21400 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21403 ClientSideWeakPassword: function (pwd)
21405 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21408 })//<script type="text/javascript">
21411 * Based Ext JS Library 1.1.1
21412 * Copyright(c) 2006-2007, Ext JS, LLC.
21418 * @class Roo.HtmlEditorCore
21419 * @extends Roo.Component
21420 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21422 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21425 Roo.HtmlEditorCore = function(config){
21428 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21433 * @event initialize
21434 * Fires when the editor is fully initialized (including the iframe)
21435 * @param {Roo.HtmlEditorCore} this
21440 * Fires when the editor is first receives the focus. Any insertion must wait
21441 * until after this event.
21442 * @param {Roo.HtmlEditorCore} this
21446 * @event beforesync
21447 * Fires before the textarea is updated with content from the editor iframe. Return false
21448 * to cancel the sync.
21449 * @param {Roo.HtmlEditorCore} this
21450 * @param {String} html
21454 * @event beforepush
21455 * Fires before the iframe editor is updated with content from the textarea. Return false
21456 * to cancel the push.
21457 * @param {Roo.HtmlEditorCore} this
21458 * @param {String} html
21463 * Fires when the textarea is updated with content from the editor iframe.
21464 * @param {Roo.HtmlEditorCore} this
21465 * @param {String} html
21470 * Fires when the iframe editor is updated with content from the textarea.
21471 * @param {Roo.HtmlEditorCore} this
21472 * @param {String} html
21477 * @event editorevent
21478 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21479 * @param {Roo.HtmlEditorCore} this
21485 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21487 // defaults : white / black...
21488 this.applyBlacklists();
21495 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21499 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21505 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21510 * @cfg {Number} height (in pixels)
21514 * @cfg {Number} width (in pixels)
21519 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21522 stylesheets: false,
21527 // private properties
21528 validationEvent : false,
21530 initialized : false,
21532 sourceEditMode : false,
21533 onFocus : Roo.emptyFn,
21535 hideMode:'offsets',
21539 // blacklist + whitelisted elements..
21546 * Protected method that will not generally be called directly. It
21547 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21548 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21550 getDocMarkup : function(){
21554 // inherit styels from page...??
21555 if (this.stylesheets === false) {
21557 Roo.get(document.head).select('style').each(function(node) {
21558 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21561 Roo.get(document.head).select('link').each(function(node) {
21562 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21565 } else if (!this.stylesheets.length) {
21567 st = '<style type="text/css">' +
21568 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21571 st = '<style type="text/css">' +
21576 st += '<style type="text/css">' +
21577 'IMG { cursor: pointer } ' +
21580 var cls = 'roo-htmleditor-body';
21582 if(this.bodyCls.length){
21583 cls += ' ' + this.bodyCls;
21586 return '<html><head>' + st +
21587 //<style type="text/css">' +
21588 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21590 ' </head><body class="' + cls + '"></body></html>';
21594 onRender : function(ct, position)
21597 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21598 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21601 this.el.dom.style.border = '0 none';
21602 this.el.dom.setAttribute('tabIndex', -1);
21603 this.el.addClass('x-hidden hide');
21607 if(Roo.isIE){ // fix IE 1px bogus margin
21608 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21612 this.frameId = Roo.id();
21616 var iframe = this.owner.wrap.createChild({
21618 cls: 'form-control', // bootstrap..
21620 name: this.frameId,
21621 frameBorder : 'no',
21622 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21627 this.iframe = iframe.dom;
21629 this.assignDocWin();
21631 this.doc.designMode = 'on';
21634 this.doc.write(this.getDocMarkup());
21638 var task = { // must defer to wait for browser to be ready
21640 //console.log("run task?" + this.doc.readyState);
21641 this.assignDocWin();
21642 if(this.doc.body || this.doc.readyState == 'complete'){
21644 this.doc.designMode="on";
21648 Roo.TaskMgr.stop(task);
21649 this.initEditor.defer(10, this);
21656 Roo.TaskMgr.start(task);
21661 onResize : function(w, h)
21663 Roo.log('resize: ' +w + ',' + h );
21664 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21668 if(typeof w == 'number'){
21670 this.iframe.style.width = w + 'px';
21672 if(typeof h == 'number'){
21674 this.iframe.style.height = h + 'px';
21676 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21683 * Toggles the editor between standard and source edit mode.
21684 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21686 toggleSourceEdit : function(sourceEditMode){
21688 this.sourceEditMode = sourceEditMode === true;
21690 if(this.sourceEditMode){
21692 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21695 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21696 //this.iframe.className = '';
21699 //this.setSize(this.owner.wrap.getSize());
21700 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21707 * Protected method that will not generally be called directly. If you need/want
21708 * custom HTML cleanup, this is the method you should override.
21709 * @param {String} html The HTML to be cleaned
21710 * return {String} The cleaned HTML
21712 cleanHtml : function(html){
21713 html = String(html);
21714 if(html.length > 5){
21715 if(Roo.isSafari){ // strip safari nonsense
21716 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21719 if(html == ' '){
21726 * HTML Editor -> Textarea
21727 * Protected method that will not generally be called directly. Syncs the contents
21728 * of the editor iframe with the textarea.
21730 syncValue : function(){
21731 if(this.initialized){
21732 var bd = (this.doc.body || this.doc.documentElement);
21733 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21734 var html = bd.innerHTML;
21736 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21737 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21739 html = '<div style="'+m[0]+'">' + html + '</div>';
21742 html = this.cleanHtml(html);
21743 // fix up the special chars.. normaly like back quotes in word...
21744 // however we do not want to do this with chinese..
21745 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21746 var cc = b.charCodeAt();
21748 (cc >= 0x4E00 && cc < 0xA000 ) ||
21749 (cc >= 0x3400 && cc < 0x4E00 ) ||
21750 (cc >= 0xf900 && cc < 0xfb00 )
21756 if(this.owner.fireEvent('beforesync', this, html) !== false){
21757 this.el.dom.value = html;
21758 this.owner.fireEvent('sync', this, html);
21764 * Protected method that will not generally be called directly. Pushes the value of the textarea
21765 * into the iframe editor.
21767 pushValue : function(){
21768 if(this.initialized){
21769 var v = this.el.dom.value.trim();
21771 // if(v.length < 1){
21775 if(this.owner.fireEvent('beforepush', this, v) !== false){
21776 var d = (this.doc.body || this.doc.documentElement);
21778 this.cleanUpPaste();
21779 this.el.dom.value = d.innerHTML;
21780 this.owner.fireEvent('push', this, v);
21786 deferFocus : function(){
21787 this.focus.defer(10, this);
21791 focus : function(){
21792 if(this.win && !this.sourceEditMode){
21799 assignDocWin: function()
21801 var iframe = this.iframe;
21804 this.doc = iframe.contentWindow.document;
21805 this.win = iframe.contentWindow;
21807 // if (!Roo.get(this.frameId)) {
21810 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21811 // this.win = Roo.get(this.frameId).dom.contentWindow;
21813 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21817 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21818 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21823 initEditor : function(){
21824 //console.log("INIT EDITOR");
21825 this.assignDocWin();
21829 this.doc.designMode="on";
21831 this.doc.write(this.getDocMarkup());
21834 var dbody = (this.doc.body || this.doc.documentElement);
21835 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21836 // this copies styles from the containing element into thsi one..
21837 // not sure why we need all of this..
21838 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21840 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21841 //ss['background-attachment'] = 'fixed'; // w3c
21842 dbody.bgProperties = 'fixed'; // ie
21843 //Roo.DomHelper.applyStyles(dbody, ss);
21844 Roo.EventManager.on(this.doc, {
21845 //'mousedown': this.onEditorEvent,
21846 'mouseup': this.onEditorEvent,
21847 'dblclick': this.onEditorEvent,
21848 'click': this.onEditorEvent,
21849 'keyup': this.onEditorEvent,
21854 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21856 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21857 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21859 this.initialized = true;
21861 this.owner.fireEvent('initialize', this);
21866 onDestroy : function(){
21872 //for (var i =0; i < this.toolbars.length;i++) {
21873 // // fixme - ask toolbars for heights?
21874 // this.toolbars[i].onDestroy();
21877 //this.wrap.dom.innerHTML = '';
21878 //this.wrap.remove();
21883 onFirstFocus : function(){
21885 this.assignDocWin();
21888 this.activated = true;
21891 if(Roo.isGecko){ // prevent silly gecko errors
21893 var s = this.win.getSelection();
21894 if(!s.focusNode || s.focusNode.nodeType != 3){
21895 var r = s.getRangeAt(0);
21896 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21901 this.execCmd('useCSS', true);
21902 this.execCmd('styleWithCSS', false);
21905 this.owner.fireEvent('activate', this);
21909 adjustFont: function(btn){
21910 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21911 //if(Roo.isSafari){ // safari
21914 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21915 if(Roo.isSafari){ // safari
21916 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21917 v = (v < 10) ? 10 : v;
21918 v = (v > 48) ? 48 : v;
21919 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21924 v = Math.max(1, v+adjust);
21926 this.execCmd('FontSize', v );
21929 onEditorEvent : function(e)
21931 this.owner.fireEvent('editorevent', this, e);
21932 // this.updateToolbar();
21933 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21936 insertTag : function(tg)
21938 // could be a bit smarter... -> wrap the current selected tRoo..
21939 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21941 range = this.createRange(this.getSelection());
21942 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21943 wrappingNode.appendChild(range.extractContents());
21944 range.insertNode(wrappingNode);
21951 this.execCmd("formatblock", tg);
21955 insertText : function(txt)
21959 var range = this.createRange();
21960 range.deleteContents();
21961 //alert(Sender.getAttribute('label'));
21963 range.insertNode(this.doc.createTextNode(txt));
21969 * Executes a Midas editor command on the editor document and performs necessary focus and
21970 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21971 * @param {String} cmd The Midas command
21972 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21974 relayCmd : function(cmd, value){
21976 this.execCmd(cmd, value);
21977 this.owner.fireEvent('editorevent', this);
21978 //this.updateToolbar();
21979 this.owner.deferFocus();
21983 * Executes a Midas editor command directly on the editor document.
21984 * For visual commands, you should use {@link #relayCmd} instead.
21985 * <b>This should only be called after the editor is initialized.</b>
21986 * @param {String} cmd The Midas command
21987 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21989 execCmd : function(cmd, value){
21990 this.doc.execCommand(cmd, false, value === undefined ? null : value);
21997 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
21999 * @param {String} text | dom node..
22001 insertAtCursor : function(text)
22004 if(!this.activated){
22010 var r = this.doc.selection.createRange();
22021 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22025 // from jquery ui (MIT licenced)
22027 var win = this.win;
22029 if (win.getSelection && win.getSelection().getRangeAt) {
22030 range = win.getSelection().getRangeAt(0);
22031 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22032 range.insertNode(node);
22033 } else if (win.document.selection && win.document.selection.createRange) {
22034 // no firefox support
22035 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22036 win.document.selection.createRange().pasteHTML(txt);
22038 // no firefox support
22039 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22040 this.execCmd('InsertHTML', txt);
22049 mozKeyPress : function(e){
22051 var c = e.getCharCode(), cmd;
22054 c = String.fromCharCode(c).toLowerCase();
22068 this.cleanUpPaste.defer(100, this);
22076 e.preventDefault();
22084 fixKeys : function(){ // load time branching for fastest keydown performance
22086 return function(e){
22087 var k = e.getKey(), r;
22090 r = this.doc.selection.createRange();
22093 r.pasteHTML('    ');
22100 r = this.doc.selection.createRange();
22102 var target = r.parentElement();
22103 if(!target || target.tagName.toLowerCase() != 'li'){
22105 r.pasteHTML('<br />');
22111 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22112 this.cleanUpPaste.defer(100, this);
22118 }else if(Roo.isOpera){
22119 return function(e){
22120 var k = e.getKey();
22124 this.execCmd('InsertHTML','    ');
22127 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22128 this.cleanUpPaste.defer(100, this);
22133 }else if(Roo.isSafari){
22134 return function(e){
22135 var k = e.getKey();
22139 this.execCmd('InsertText','\t');
22143 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22144 this.cleanUpPaste.defer(100, this);
22152 getAllAncestors: function()
22154 var p = this.getSelectedNode();
22157 a.push(p); // push blank onto stack..
22158 p = this.getParentElement();
22162 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22166 a.push(this.doc.body);
22170 lastSelNode : false,
22173 getSelection : function()
22175 this.assignDocWin();
22176 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22179 getSelectedNode: function()
22181 // this may only work on Gecko!!!
22183 // should we cache this!!!!
22188 var range = this.createRange(this.getSelection()).cloneRange();
22191 var parent = range.parentElement();
22193 var testRange = range.duplicate();
22194 testRange.moveToElementText(parent);
22195 if (testRange.inRange(range)) {
22198 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22201 parent = parent.parentElement;
22206 // is ancestor a text element.
22207 var ac = range.commonAncestorContainer;
22208 if (ac.nodeType == 3) {
22209 ac = ac.parentNode;
22212 var ar = ac.childNodes;
22215 var other_nodes = [];
22216 var has_other_nodes = false;
22217 for (var i=0;i<ar.length;i++) {
22218 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22221 // fullly contained node.
22223 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22228 // probably selected..
22229 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22230 other_nodes.push(ar[i]);
22234 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22239 has_other_nodes = true;
22241 if (!nodes.length && other_nodes.length) {
22242 nodes= other_nodes;
22244 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22250 createRange: function(sel)
22252 // this has strange effects when using with
22253 // top toolbar - not sure if it's a great idea.
22254 //this.editor.contentWindow.focus();
22255 if (typeof sel != "undefined") {
22257 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22259 return this.doc.createRange();
22262 return this.doc.createRange();
22265 getParentElement: function()
22268 this.assignDocWin();
22269 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22271 var range = this.createRange(sel);
22274 var p = range.commonAncestorContainer;
22275 while (p.nodeType == 3) { // text node
22286 * Range intersection.. the hard stuff...
22290 * [ -- selected range --- ]
22294 * if end is before start or hits it. fail.
22295 * if start is after end or hits it fail.
22297 * if either hits (but other is outside. - then it's not
22303 // @see http://www.thismuchiknow.co.uk/?p=64.
22304 rangeIntersectsNode : function(range, node)
22306 var nodeRange = node.ownerDocument.createRange();
22308 nodeRange.selectNode(node);
22310 nodeRange.selectNodeContents(node);
22313 var rangeStartRange = range.cloneRange();
22314 rangeStartRange.collapse(true);
22316 var rangeEndRange = range.cloneRange();
22317 rangeEndRange.collapse(false);
22319 var nodeStartRange = nodeRange.cloneRange();
22320 nodeStartRange.collapse(true);
22322 var nodeEndRange = nodeRange.cloneRange();
22323 nodeEndRange.collapse(false);
22325 return rangeStartRange.compareBoundaryPoints(
22326 Range.START_TO_START, nodeEndRange) == -1 &&
22327 rangeEndRange.compareBoundaryPoints(
22328 Range.START_TO_START, nodeStartRange) == 1;
22332 rangeCompareNode : function(range, node)
22334 var nodeRange = node.ownerDocument.createRange();
22336 nodeRange.selectNode(node);
22338 nodeRange.selectNodeContents(node);
22342 range.collapse(true);
22344 nodeRange.collapse(true);
22346 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22347 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22349 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22351 var nodeIsBefore = ss == 1;
22352 var nodeIsAfter = ee == -1;
22354 if (nodeIsBefore && nodeIsAfter) {
22357 if (!nodeIsBefore && nodeIsAfter) {
22358 return 1; //right trailed.
22361 if (nodeIsBefore && !nodeIsAfter) {
22362 return 2; // left trailed.
22368 // private? - in a new class?
22369 cleanUpPaste : function()
22371 // cleans up the whole document..
22372 Roo.log('cleanuppaste');
22374 this.cleanUpChildren(this.doc.body);
22375 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22376 if (clean != this.doc.body.innerHTML) {
22377 this.doc.body.innerHTML = clean;
22382 cleanWordChars : function(input) {// change the chars to hex code
22383 var he = Roo.HtmlEditorCore;
22385 var output = input;
22386 Roo.each(he.swapCodes, function(sw) {
22387 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22389 output = output.replace(swapper, sw[1]);
22396 cleanUpChildren : function (n)
22398 if (!n.childNodes.length) {
22401 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22402 this.cleanUpChild(n.childNodes[i]);
22409 cleanUpChild : function (node)
22412 //console.log(node);
22413 if (node.nodeName == "#text") {
22414 // clean up silly Windows -- stuff?
22417 if (node.nodeName == "#comment") {
22418 node.parentNode.removeChild(node);
22419 // clean up silly Windows -- stuff?
22422 var lcname = node.tagName.toLowerCase();
22423 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22424 // whitelist of tags..
22426 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22428 node.parentNode.removeChild(node);
22433 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22435 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22436 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22438 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22439 // remove_keep_children = true;
22442 if (remove_keep_children) {
22443 this.cleanUpChildren(node);
22444 // inserts everything just before this node...
22445 while (node.childNodes.length) {
22446 var cn = node.childNodes[0];
22447 node.removeChild(cn);
22448 node.parentNode.insertBefore(cn, node);
22450 node.parentNode.removeChild(node);
22454 if (!node.attributes || !node.attributes.length) {
22455 this.cleanUpChildren(node);
22459 function cleanAttr(n,v)
22462 if (v.match(/^\./) || v.match(/^\//)) {
22465 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22468 if (v.match(/^#/)) {
22471 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22472 node.removeAttribute(n);
22476 var cwhite = this.cwhite;
22477 var cblack = this.cblack;
22479 function cleanStyle(n,v)
22481 if (v.match(/expression/)) { //XSS?? should we even bother..
22482 node.removeAttribute(n);
22486 var parts = v.split(/;/);
22489 Roo.each(parts, function(p) {
22490 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22494 var l = p.split(':').shift().replace(/\s+/g,'');
22495 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22497 if ( cwhite.length && cblack.indexOf(l) > -1) {
22498 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22499 //node.removeAttribute(n);
22503 // only allow 'c whitelisted system attributes'
22504 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22505 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22506 //node.removeAttribute(n);
22516 if (clean.length) {
22517 node.setAttribute(n, clean.join(';'));
22519 node.removeAttribute(n);
22525 for (var i = node.attributes.length-1; i > -1 ; i--) {
22526 var a = node.attributes[i];
22529 if (a.name.toLowerCase().substr(0,2)=='on') {
22530 node.removeAttribute(a.name);
22533 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22534 node.removeAttribute(a.name);
22537 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22538 cleanAttr(a.name,a.value); // fixme..
22541 if (a.name == 'style') {
22542 cleanStyle(a.name,a.value);
22545 /// clean up MS crap..
22546 // tecnically this should be a list of valid class'es..
22549 if (a.name == 'class') {
22550 if (a.value.match(/^Mso/)) {
22551 node.className = '';
22554 if (a.value.match(/^body$/)) {
22555 node.className = '';
22566 this.cleanUpChildren(node);
22572 * Clean up MS wordisms...
22574 cleanWord : function(node)
22579 this.cleanWord(this.doc.body);
22582 if (node.nodeName == "#text") {
22583 // clean up silly Windows -- stuff?
22586 if (node.nodeName == "#comment") {
22587 node.parentNode.removeChild(node);
22588 // clean up silly Windows -- stuff?
22592 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22593 node.parentNode.removeChild(node);
22597 // remove - but keep children..
22598 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22599 while (node.childNodes.length) {
22600 var cn = node.childNodes[0];
22601 node.removeChild(cn);
22602 node.parentNode.insertBefore(cn, node);
22604 node.parentNode.removeChild(node);
22605 this.iterateChildren(node, this.cleanWord);
22609 if (node.className.length) {
22611 var cn = node.className.split(/\W+/);
22613 Roo.each(cn, function(cls) {
22614 if (cls.match(/Mso[a-zA-Z]+/)) {
22619 node.className = cna.length ? cna.join(' ') : '';
22621 node.removeAttribute("class");
22625 if (node.hasAttribute("lang")) {
22626 node.removeAttribute("lang");
22629 if (node.hasAttribute("style")) {
22631 var styles = node.getAttribute("style").split(";");
22633 Roo.each(styles, function(s) {
22634 if (!s.match(/:/)) {
22637 var kv = s.split(":");
22638 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22641 // what ever is left... we allow.
22644 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22645 if (!nstyle.length) {
22646 node.removeAttribute('style');
22649 this.iterateChildren(node, this.cleanWord);
22655 * iterateChildren of a Node, calling fn each time, using this as the scole..
22656 * @param {DomNode} node node to iterate children of.
22657 * @param {Function} fn method of this class to call on each item.
22659 iterateChildren : function(node, fn)
22661 if (!node.childNodes.length) {
22664 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22665 fn.call(this, node.childNodes[i])
22671 * cleanTableWidths.
22673 * Quite often pasting from word etc.. results in tables with column and widths.
22674 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22677 cleanTableWidths : function(node)
22682 this.cleanTableWidths(this.doc.body);
22687 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22690 Roo.log(node.tagName);
22691 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22692 this.iterateChildren(node, this.cleanTableWidths);
22695 if (node.hasAttribute('width')) {
22696 node.removeAttribute('width');
22700 if (node.hasAttribute("style")) {
22703 var styles = node.getAttribute("style").split(";");
22705 Roo.each(styles, function(s) {
22706 if (!s.match(/:/)) {
22709 var kv = s.split(":");
22710 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22713 // what ever is left... we allow.
22716 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22717 if (!nstyle.length) {
22718 node.removeAttribute('style');
22722 this.iterateChildren(node, this.cleanTableWidths);
22730 domToHTML : function(currentElement, depth, nopadtext) {
22732 depth = depth || 0;
22733 nopadtext = nopadtext || false;
22735 if (!currentElement) {
22736 return this.domToHTML(this.doc.body);
22739 //Roo.log(currentElement);
22741 var allText = false;
22742 var nodeName = currentElement.nodeName;
22743 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22745 if (nodeName == '#text') {
22747 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22752 if (nodeName != 'BODY') {
22755 // Prints the node tagName, such as <A>, <IMG>, etc
22758 for(i = 0; i < currentElement.attributes.length;i++) {
22760 var aname = currentElement.attributes.item(i).name;
22761 if (!currentElement.attributes.item(i).value.length) {
22764 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22767 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22776 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22779 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22784 // Traverse the tree
22786 var currentElementChild = currentElement.childNodes.item(i);
22787 var allText = true;
22788 var innerHTML = '';
22790 while (currentElementChild) {
22791 // Formatting code (indent the tree so it looks nice on the screen)
22792 var nopad = nopadtext;
22793 if (lastnode == 'SPAN') {
22797 if (currentElementChild.nodeName == '#text') {
22798 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22799 toadd = nopadtext ? toadd : toadd.trim();
22800 if (!nopad && toadd.length > 80) {
22801 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22803 innerHTML += toadd;
22806 currentElementChild = currentElement.childNodes.item(i);
22812 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22814 // Recursively traverse the tree structure of the child node
22815 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22816 lastnode = currentElementChild.nodeName;
22818 currentElementChild=currentElement.childNodes.item(i);
22824 // The remaining code is mostly for formatting the tree
22825 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22830 ret+= "</"+tagName+">";
22836 applyBlacklists : function()
22838 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22839 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22843 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22844 if (b.indexOf(tag) > -1) {
22847 this.white.push(tag);
22851 Roo.each(w, function(tag) {
22852 if (b.indexOf(tag) > -1) {
22855 if (this.white.indexOf(tag) > -1) {
22858 this.white.push(tag);
22863 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22864 if (w.indexOf(tag) > -1) {
22867 this.black.push(tag);
22871 Roo.each(b, function(tag) {
22872 if (w.indexOf(tag) > -1) {
22875 if (this.black.indexOf(tag) > -1) {
22878 this.black.push(tag);
22883 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22884 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22888 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22889 if (b.indexOf(tag) > -1) {
22892 this.cwhite.push(tag);
22896 Roo.each(w, function(tag) {
22897 if (b.indexOf(tag) > -1) {
22900 if (this.cwhite.indexOf(tag) > -1) {
22903 this.cwhite.push(tag);
22908 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22909 if (w.indexOf(tag) > -1) {
22912 this.cblack.push(tag);
22916 Roo.each(b, function(tag) {
22917 if (w.indexOf(tag) > -1) {
22920 if (this.cblack.indexOf(tag) > -1) {
22923 this.cblack.push(tag);
22928 setStylesheets : function(stylesheets)
22930 if(typeof(stylesheets) == 'string'){
22931 Roo.get(this.iframe.contentDocument.head).createChild({
22933 rel : 'stylesheet',
22942 Roo.each(stylesheets, function(s) {
22947 Roo.get(_this.iframe.contentDocument.head).createChild({
22949 rel : 'stylesheet',
22958 removeStylesheets : function()
22962 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22967 setStyle : function(style)
22969 Roo.get(this.iframe.contentDocument.head).createChild({
22978 // hide stuff that is not compatible
22992 * @event specialkey
22996 * @cfg {String} fieldClass @hide
22999 * @cfg {String} focusClass @hide
23002 * @cfg {String} autoCreate @hide
23005 * @cfg {String} inputType @hide
23008 * @cfg {String} invalidClass @hide
23011 * @cfg {String} invalidText @hide
23014 * @cfg {String} msgFx @hide
23017 * @cfg {String} validateOnBlur @hide
23021 Roo.HtmlEditorCore.white = [
23022 'area', 'br', 'img', 'input', 'hr', 'wbr',
23024 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23025 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23026 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23027 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23028 'table', 'ul', 'xmp',
23030 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23033 'dir', 'menu', 'ol', 'ul', 'dl',
23039 Roo.HtmlEditorCore.black = [
23040 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23042 'base', 'basefont', 'bgsound', 'blink', 'body',
23043 'frame', 'frameset', 'head', 'html', 'ilayer',
23044 'iframe', 'layer', 'link', 'meta', 'object',
23045 'script', 'style' ,'title', 'xml' // clean later..
23047 Roo.HtmlEditorCore.clean = [
23048 'script', 'style', 'title', 'xml'
23050 Roo.HtmlEditorCore.remove = [
23055 Roo.HtmlEditorCore.ablack = [
23059 Roo.HtmlEditorCore.aclean = [
23060 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23064 Roo.HtmlEditorCore.pwhite= [
23065 'http', 'https', 'mailto'
23068 // white listed style attributes.
23069 Roo.HtmlEditorCore.cwhite= [
23070 // 'text-align', /// default is to allow most things..
23076 // black listed style attributes.
23077 Roo.HtmlEditorCore.cblack= [
23078 // 'font-size' -- this can be set by the project
23082 Roo.HtmlEditorCore.swapCodes =[
23101 * @class Roo.bootstrap.HtmlEditor
23102 * @extends Roo.bootstrap.TextArea
23103 * Bootstrap HtmlEditor class
23106 * Create a new HtmlEditor
23107 * @param {Object} config The config object
23110 Roo.bootstrap.HtmlEditor = function(config){
23111 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23112 if (!this.toolbars) {
23113 this.toolbars = [];
23116 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23119 * @event initialize
23120 * Fires when the editor is fully initialized (including the iframe)
23121 * @param {HtmlEditor} this
23126 * Fires when the editor is first receives the focus. Any insertion must wait
23127 * until after this event.
23128 * @param {HtmlEditor} this
23132 * @event beforesync
23133 * Fires before the textarea is updated with content from the editor iframe. Return false
23134 * to cancel the sync.
23135 * @param {HtmlEditor} this
23136 * @param {String} html
23140 * @event beforepush
23141 * Fires before the iframe editor is updated with content from the textarea. Return false
23142 * to cancel the push.
23143 * @param {HtmlEditor} this
23144 * @param {String} html
23149 * Fires when the textarea is updated with content from the editor iframe.
23150 * @param {HtmlEditor} this
23151 * @param {String} html
23156 * Fires when the iframe editor is updated with content from the textarea.
23157 * @param {HtmlEditor} this
23158 * @param {String} html
23162 * @event editmodechange
23163 * Fires when the editor switches edit modes
23164 * @param {HtmlEditor} this
23165 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23167 editmodechange: true,
23169 * @event editorevent
23170 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23171 * @param {HtmlEditor} this
23175 * @event firstfocus
23176 * Fires when on first focus - needed by toolbars..
23177 * @param {HtmlEditor} this
23182 * Auto save the htmlEditor value as a file into Events
23183 * @param {HtmlEditor} this
23187 * @event savedpreview
23188 * preview the saved version of htmlEditor
23189 * @param {HtmlEditor} this
23196 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23200 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23205 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23210 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23215 * @cfg {Number} height (in pixels)
23219 * @cfg {Number} width (in pixels)
23224 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23227 stylesheets: false,
23232 // private properties
23233 validationEvent : false,
23235 initialized : false,
23238 onFocus : Roo.emptyFn,
23240 hideMode:'offsets',
23242 tbContainer : false,
23246 toolbarContainer :function() {
23247 return this.wrap.select('.x-html-editor-tb',true).first();
23251 * Protected method that will not generally be called directly. It
23252 * is called when the editor creates its toolbar. Override this method if you need to
23253 * add custom toolbar buttons.
23254 * @param {HtmlEditor} editor
23256 createToolbar : function(){
23257 Roo.log('renewing');
23258 Roo.log("create toolbars");
23260 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23261 this.toolbars[0].render(this.toolbarContainer());
23265 // if (!editor.toolbars || !editor.toolbars.length) {
23266 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23269 // for (var i =0 ; i < editor.toolbars.length;i++) {
23270 // editor.toolbars[i] = Roo.factory(
23271 // typeof(editor.toolbars[i]) == 'string' ?
23272 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23273 // Roo.bootstrap.HtmlEditor);
23274 // editor.toolbars[i].init(editor);
23280 onRender : function(ct, position)
23282 // Roo.log("Call onRender: " + this.xtype);
23284 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23286 this.wrap = this.inputEl().wrap({
23287 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23290 this.editorcore.onRender(ct, position);
23292 if (this.resizable) {
23293 this.resizeEl = new Roo.Resizable(this.wrap, {
23297 minHeight : this.height,
23298 height: this.height,
23299 handles : this.resizable,
23302 resize : function(r, w, h) {
23303 _t.onResize(w,h); // -something
23309 this.createToolbar(this);
23312 if(!this.width && this.resizable){
23313 this.setSize(this.wrap.getSize());
23315 if (this.resizeEl) {
23316 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23317 // should trigger onReize..
23323 onResize : function(w, h)
23325 Roo.log('resize: ' +w + ',' + h );
23326 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23330 if(this.inputEl() ){
23331 if(typeof w == 'number'){
23332 var aw = w - this.wrap.getFrameWidth('lr');
23333 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23336 if(typeof h == 'number'){
23337 var tbh = -11; // fixme it needs to tool bar size!
23338 for (var i =0; i < this.toolbars.length;i++) {
23339 // fixme - ask toolbars for heights?
23340 tbh += this.toolbars[i].el.getHeight();
23341 //if (this.toolbars[i].footer) {
23342 // tbh += this.toolbars[i].footer.el.getHeight();
23350 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23351 ah -= 5; // knock a few pixes off for look..
23352 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23356 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23357 this.editorcore.onResize(ew,eh);
23362 * Toggles the editor between standard and source edit mode.
23363 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23365 toggleSourceEdit : function(sourceEditMode)
23367 this.editorcore.toggleSourceEdit(sourceEditMode);
23369 if(this.editorcore.sourceEditMode){
23370 Roo.log('editor - showing textarea');
23373 // Roo.log(this.syncValue());
23375 this.inputEl().removeClass(['hide', 'x-hidden']);
23376 this.inputEl().dom.removeAttribute('tabIndex');
23377 this.inputEl().focus();
23379 Roo.log('editor - hiding textarea');
23381 // Roo.log(this.pushValue());
23384 this.inputEl().addClass(['hide', 'x-hidden']);
23385 this.inputEl().dom.setAttribute('tabIndex', -1);
23386 //this.deferFocus();
23389 if(this.resizable){
23390 this.setSize(this.wrap.getSize());
23393 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23396 // private (for BoxComponent)
23397 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23399 // private (for BoxComponent)
23400 getResizeEl : function(){
23404 // private (for BoxComponent)
23405 getPositionEl : function(){
23410 initEvents : function(){
23411 this.originalValue = this.getValue();
23415 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23418 // markInvalid : Roo.emptyFn,
23420 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23423 // clearInvalid : Roo.emptyFn,
23425 setValue : function(v){
23426 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23427 this.editorcore.pushValue();
23432 deferFocus : function(){
23433 this.focus.defer(10, this);
23437 focus : function(){
23438 this.editorcore.focus();
23444 onDestroy : function(){
23450 for (var i =0; i < this.toolbars.length;i++) {
23451 // fixme - ask toolbars for heights?
23452 this.toolbars[i].onDestroy();
23455 this.wrap.dom.innerHTML = '';
23456 this.wrap.remove();
23461 onFirstFocus : function(){
23462 //Roo.log("onFirstFocus");
23463 this.editorcore.onFirstFocus();
23464 for (var i =0; i < this.toolbars.length;i++) {
23465 this.toolbars[i].onFirstFocus();
23471 syncValue : function()
23473 this.editorcore.syncValue();
23476 pushValue : function()
23478 this.editorcore.pushValue();
23482 // hide stuff that is not compatible
23496 * @event specialkey
23500 * @cfg {String} fieldClass @hide
23503 * @cfg {String} focusClass @hide
23506 * @cfg {String} autoCreate @hide
23509 * @cfg {String} inputType @hide
23512 * @cfg {String} invalidClass @hide
23515 * @cfg {String} invalidText @hide
23518 * @cfg {String} msgFx @hide
23521 * @cfg {String} validateOnBlur @hide
23530 Roo.namespace('Roo.bootstrap.htmleditor');
23532 * @class Roo.bootstrap.HtmlEditorToolbar1
23537 new Roo.bootstrap.HtmlEditor({
23540 new Roo.bootstrap.HtmlEditorToolbar1({
23541 disable : { fonts: 1 , format: 1, ..., ... , ...],
23547 * @cfg {Object} disable List of elements to disable..
23548 * @cfg {Array} btns List of additional buttons.
23552 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23555 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23558 Roo.apply(this, config);
23560 // default disabled, based on 'good practice'..
23561 this.disable = this.disable || {};
23562 Roo.applyIf(this.disable, {
23565 specialElements : true
23567 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23569 this.editor = config.editor;
23570 this.editorcore = config.editor.editorcore;
23572 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23574 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23575 // dont call parent... till later.
23577 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23582 editorcore : false,
23587 "h1","h2","h3","h4","h5","h6",
23589 "abbr", "acronym", "address", "cite", "samp", "var",
23593 onRender : function(ct, position)
23595 // Roo.log("Call onRender: " + this.xtype);
23597 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23599 this.el.dom.style.marginBottom = '0';
23601 var editorcore = this.editorcore;
23602 var editor= this.editor;
23605 var btn = function(id,cmd , toggle, handler, html){
23607 var event = toggle ? 'toggle' : 'click';
23612 xns: Roo.bootstrap,
23615 enableToggle:toggle !== false,
23617 pressed : toggle ? false : null,
23620 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23621 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23627 // var cb_box = function...
23632 xns: Roo.bootstrap,
23633 glyphicon : 'font',
23637 xns: Roo.bootstrap,
23641 Roo.each(this.formats, function(f) {
23642 style.menu.items.push({
23644 xns: Roo.bootstrap,
23645 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23650 editorcore.insertTag(this.tagname);
23657 children.push(style);
23659 btn('bold',false,true);
23660 btn('italic',false,true);
23661 btn('align-left', 'justifyleft',true);
23662 btn('align-center', 'justifycenter',true);
23663 btn('align-right' , 'justifyright',true);
23664 btn('link', false, false, function(btn) {
23665 //Roo.log("create link?");
23666 var url = prompt(this.createLinkText, this.defaultLinkValue);
23667 if(url && url != 'http:/'+'/'){
23668 this.editorcore.relayCmd('createlink', url);
23671 btn('list','insertunorderedlist',true);
23672 btn('pencil', false,true, function(btn){
23674 this.toggleSourceEdit(btn.pressed);
23677 if (this.editor.btns.length > 0) {
23678 for (var i = 0; i<this.editor.btns.length; i++) {
23679 children.push(this.editor.btns[i]);
23687 xns: Roo.bootstrap,
23692 xns: Roo.bootstrap,
23697 cog.menu.items.push({
23699 xns: Roo.bootstrap,
23700 html : Clean styles,
23705 editorcore.insertTag(this.tagname);
23714 this.xtype = 'NavSimplebar';
23716 for(var i=0;i< children.length;i++) {
23718 this.buttons.add(this.addxtypeChild(children[i]));
23722 editor.on('editorevent', this.updateToolbar, this);
23724 onBtnClick : function(id)
23726 this.editorcore.relayCmd(id);
23727 this.editorcore.focus();
23731 * Protected method that will not generally be called directly. It triggers
23732 * a toolbar update by reading the markup state of the current selection in the editor.
23734 updateToolbar: function(){
23736 if(!this.editorcore.activated){
23737 this.editor.onFirstFocus(); // is this neeed?
23741 var btns = this.buttons;
23742 var doc = this.editorcore.doc;
23743 btns.get('bold').setActive(doc.queryCommandState('bold'));
23744 btns.get('italic').setActive(doc.queryCommandState('italic'));
23745 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23747 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23748 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23749 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23751 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23752 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23755 var ans = this.editorcore.getAllAncestors();
23756 if (this.formatCombo) {
23759 var store = this.formatCombo.store;
23760 this.formatCombo.setValue("");
23761 for (var i =0; i < ans.length;i++) {
23762 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23764 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23772 // hides menus... - so this cant be on a menu...
23773 Roo.bootstrap.MenuMgr.hideAll();
23775 Roo.bootstrap.MenuMgr.hideAll();
23776 //this.editorsyncValue();
23778 onFirstFocus: function() {
23779 this.buttons.each(function(item){
23783 toggleSourceEdit : function(sourceEditMode){
23786 if(sourceEditMode){
23787 Roo.log("disabling buttons");
23788 this.buttons.each( function(item){
23789 if(item.cmd != 'pencil'){
23795 Roo.log("enabling buttons");
23796 if(this.editorcore.initialized){
23797 this.buttons.each( function(item){
23803 Roo.log("calling toggole on editor");
23804 // tell the editor that it's been pressed..
23805 this.editor.toggleSourceEdit(sourceEditMode);
23815 * @class Roo.bootstrap.Table.AbstractSelectionModel
23816 * @extends Roo.util.Observable
23817 * Abstract base class for grid SelectionModels. It provides the interface that should be
23818 * implemented by descendant classes. This class should not be directly instantiated.
23821 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23822 this.locked = false;
23823 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23827 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23828 /** @ignore Called by the grid automatically. Do not call directly. */
23829 init : function(grid){
23835 * Locks the selections.
23838 this.locked = true;
23842 * Unlocks the selections.
23844 unlock : function(){
23845 this.locked = false;
23849 * Returns true if the selections are locked.
23850 * @return {Boolean}
23852 isLocked : function(){
23853 return this.locked;
23857 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23858 * @class Roo.bootstrap.Table.RowSelectionModel
23859 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23860 * It supports multiple selections and keyboard selection/navigation.
23862 * @param {Object} config
23865 Roo.bootstrap.Table.RowSelectionModel = function(config){
23866 Roo.apply(this, config);
23867 this.selections = new Roo.util.MixedCollection(false, function(o){
23872 this.lastActive = false;
23876 * @event selectionchange
23877 * Fires when the selection changes
23878 * @param {SelectionModel} this
23880 "selectionchange" : true,
23882 * @event afterselectionchange
23883 * Fires after the selection changes (eg. by key press or clicking)
23884 * @param {SelectionModel} this
23886 "afterselectionchange" : true,
23888 * @event beforerowselect
23889 * Fires when a row is selected being selected, return false to cancel.
23890 * @param {SelectionModel} this
23891 * @param {Number} rowIndex The selected index
23892 * @param {Boolean} keepExisting False if other selections will be cleared
23894 "beforerowselect" : true,
23897 * Fires when a row is selected.
23898 * @param {SelectionModel} this
23899 * @param {Number} rowIndex The selected index
23900 * @param {Roo.data.Record} r The record
23902 "rowselect" : true,
23904 * @event rowdeselect
23905 * Fires when a row is deselected.
23906 * @param {SelectionModel} this
23907 * @param {Number} rowIndex The selected index
23909 "rowdeselect" : true
23911 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23912 this.locked = false;
23915 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23917 * @cfg {Boolean} singleSelect
23918 * True to allow selection of only one row at a time (defaults to false)
23920 singleSelect : false,
23923 initEvents : function()
23926 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23927 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23928 //}else{ // allow click to work like normal
23929 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23931 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23932 this.grid.on("rowclick", this.handleMouseDown, this);
23934 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23935 "up" : function(e){
23937 this.selectPrevious(e.shiftKey);
23938 }else if(this.last !== false && this.lastActive !== false){
23939 var last = this.last;
23940 this.selectRange(this.last, this.lastActive-1);
23941 this.grid.getView().focusRow(this.lastActive);
23942 if(last !== false){
23946 this.selectFirstRow();
23948 this.fireEvent("afterselectionchange", this);
23950 "down" : function(e){
23952 this.selectNext(e.shiftKey);
23953 }else if(this.last !== false && this.lastActive !== false){
23954 var last = this.last;
23955 this.selectRange(this.last, this.lastActive+1);
23956 this.grid.getView().focusRow(this.lastActive);
23957 if(last !== false){
23961 this.selectFirstRow();
23963 this.fireEvent("afterselectionchange", this);
23967 this.grid.store.on('load', function(){
23968 this.selections.clear();
23971 var view = this.grid.view;
23972 view.on("refresh", this.onRefresh, this);
23973 view.on("rowupdated", this.onRowUpdated, this);
23974 view.on("rowremoved", this.onRemove, this);
23979 onRefresh : function()
23981 var ds = this.grid.store, i, v = this.grid.view;
23982 var s = this.selections;
23983 s.each(function(r){
23984 if((i = ds.indexOfId(r.id)) != -1){
23993 onRemove : function(v, index, r){
23994 this.selections.remove(r);
23998 onRowUpdated : function(v, index, r){
23999 if(this.isSelected(r)){
24000 v.onRowSelect(index);
24006 * @param {Array} records The records to select
24007 * @param {Boolean} keepExisting (optional) True to keep existing selections
24009 selectRecords : function(records, keepExisting)
24012 this.clearSelections();
24014 var ds = this.grid.store;
24015 for(var i = 0, len = records.length; i < len; i++){
24016 this.selectRow(ds.indexOf(records[i]), true);
24021 * Gets the number of selected rows.
24024 getCount : function(){
24025 return this.selections.length;
24029 * Selects the first row in the grid.
24031 selectFirstRow : function(){
24036 * Select the last row.
24037 * @param {Boolean} keepExisting (optional) True to keep existing selections
24039 selectLastRow : function(keepExisting){
24040 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24041 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24045 * Selects the row immediately following the last selected row.
24046 * @param {Boolean} keepExisting (optional) True to keep existing selections
24048 selectNext : function(keepExisting)
24050 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24051 this.selectRow(this.last+1, keepExisting);
24052 this.grid.getView().focusRow(this.last);
24057 * Selects the row that precedes the last selected row.
24058 * @param {Boolean} keepExisting (optional) True to keep existing selections
24060 selectPrevious : function(keepExisting){
24062 this.selectRow(this.last-1, keepExisting);
24063 this.grid.getView().focusRow(this.last);
24068 * Returns the selected records
24069 * @return {Array} Array of selected records
24071 getSelections : function(){
24072 return [].concat(this.selections.items);
24076 * Returns the first selected record.
24079 getSelected : function(){
24080 return this.selections.itemAt(0);
24085 * Clears all selections.
24087 clearSelections : function(fast)
24093 var ds = this.grid.store;
24094 var s = this.selections;
24095 s.each(function(r){
24096 this.deselectRow(ds.indexOfId(r.id));
24100 this.selections.clear();
24107 * Selects all rows.
24109 selectAll : function(){
24113 this.selections.clear();
24114 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24115 this.selectRow(i, true);
24120 * Returns True if there is a selection.
24121 * @return {Boolean}
24123 hasSelection : function(){
24124 return this.selections.length > 0;
24128 * Returns True if the specified row is selected.
24129 * @param {Number/Record} record The record or index of the record to check
24130 * @return {Boolean}
24132 isSelected : function(index){
24133 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24134 return (r && this.selections.key(r.id) ? true : false);
24138 * Returns True if the specified record id is selected.
24139 * @param {String} id The id of record to check
24140 * @return {Boolean}
24142 isIdSelected : function(id){
24143 return (this.selections.key(id) ? true : false);
24148 handleMouseDBClick : function(e, t){
24152 handleMouseDown : function(e, t)
24154 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24155 if(this.isLocked() || rowIndex < 0 ){
24158 if(e.shiftKey && this.last !== false){
24159 var last = this.last;
24160 this.selectRange(last, rowIndex, e.ctrlKey);
24161 this.last = last; // reset the last
24165 var isSelected = this.isSelected(rowIndex);
24166 //Roo.log("select row:" + rowIndex);
24168 this.deselectRow(rowIndex);
24170 this.selectRow(rowIndex, true);
24174 if(e.button !== 0 && isSelected){
24175 alert('rowIndex 2: ' + rowIndex);
24176 view.focusRow(rowIndex);
24177 }else if(e.ctrlKey && isSelected){
24178 this.deselectRow(rowIndex);
24179 }else if(!isSelected){
24180 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24181 view.focusRow(rowIndex);
24185 this.fireEvent("afterselectionchange", this);
24188 handleDragableRowClick : function(grid, rowIndex, e)
24190 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24191 this.selectRow(rowIndex, false);
24192 grid.view.focusRow(rowIndex);
24193 this.fireEvent("afterselectionchange", this);
24198 * Selects multiple rows.
24199 * @param {Array} rows Array of the indexes of the row to select
24200 * @param {Boolean} keepExisting (optional) True to keep existing selections
24202 selectRows : function(rows, keepExisting){
24204 this.clearSelections();
24206 for(var i = 0, len = rows.length; i < len; i++){
24207 this.selectRow(rows[i], true);
24212 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24213 * @param {Number} startRow The index of the first row in the range
24214 * @param {Number} endRow The index of the last row in the range
24215 * @param {Boolean} keepExisting (optional) True to retain existing selections
24217 selectRange : function(startRow, endRow, keepExisting){
24222 this.clearSelections();
24224 if(startRow <= endRow){
24225 for(var i = startRow; i <= endRow; i++){
24226 this.selectRow(i, true);
24229 for(var i = startRow; i >= endRow; i--){
24230 this.selectRow(i, true);
24236 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24237 * @param {Number} startRow The index of the first row in the range
24238 * @param {Number} endRow The index of the last row in the range
24240 deselectRange : function(startRow, endRow, preventViewNotify){
24244 for(var i = startRow; i <= endRow; i++){
24245 this.deselectRow(i, preventViewNotify);
24251 * @param {Number} row The index of the row to select
24252 * @param {Boolean} keepExisting (optional) True to keep existing selections
24254 selectRow : function(index, keepExisting, preventViewNotify)
24256 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24259 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24260 if(!keepExisting || this.singleSelect){
24261 this.clearSelections();
24264 var r = this.grid.store.getAt(index);
24265 //console.log('selectRow - record id :' + r.id);
24267 this.selections.add(r);
24268 this.last = this.lastActive = index;
24269 if(!preventViewNotify){
24270 var proxy = new Roo.Element(
24271 this.grid.getRowDom(index)
24273 proxy.addClass('bg-info info');
24275 this.fireEvent("rowselect", this, index, r);
24276 this.fireEvent("selectionchange", this);
24282 * @param {Number} row The index of the row to deselect
24284 deselectRow : function(index, preventViewNotify)
24289 if(this.last == index){
24292 if(this.lastActive == index){
24293 this.lastActive = false;
24296 var r = this.grid.store.getAt(index);
24301 this.selections.remove(r);
24302 //.console.log('deselectRow - record id :' + r.id);
24303 if(!preventViewNotify){
24305 var proxy = new Roo.Element(
24306 this.grid.getRowDom(index)
24308 proxy.removeClass('bg-info info');
24310 this.fireEvent("rowdeselect", this, index);
24311 this.fireEvent("selectionchange", this);
24315 restoreLast : function(){
24317 this.last = this._last;
24322 acceptsNav : function(row, col, cm){
24323 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24327 onEditorKey : function(field, e){
24328 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24333 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24335 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24337 }else if(k == e.ENTER && !e.ctrlKey){
24341 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24343 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24345 }else if(k == e.ESC){
24349 g.startEditing(newCell[0], newCell[1]);
24355 * Ext JS Library 1.1.1
24356 * Copyright(c) 2006-2007, Ext JS, LLC.
24358 * Originally Released Under LGPL - original licence link has changed is not relivant.
24361 * <script type="text/javascript">
24365 * @class Roo.bootstrap.PagingToolbar
24366 * @extends Roo.bootstrap.NavSimplebar
24367 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24369 * Create a new PagingToolbar
24370 * @param {Object} config The config object
24371 * @param {Roo.data.Store} store
24373 Roo.bootstrap.PagingToolbar = function(config)
24375 // old args format still supported... - xtype is prefered..
24376 // created from xtype...
24378 this.ds = config.dataSource;
24380 if (config.store && !this.ds) {
24381 this.store= Roo.factory(config.store, Roo.data);
24382 this.ds = this.store;
24383 this.ds.xmodule = this.xmodule || false;
24386 this.toolbarItems = [];
24387 if (config.items) {
24388 this.toolbarItems = config.items;
24391 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24396 this.bind(this.ds);
24399 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24403 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24405 * @cfg {Roo.data.Store} dataSource
24406 * The underlying data store providing the paged data
24409 * @cfg {String/HTMLElement/Element} container
24410 * container The id or element that will contain the toolbar
24413 * @cfg {Boolean} displayInfo
24414 * True to display the displayMsg (defaults to false)
24417 * @cfg {Number} pageSize
24418 * The number of records to display per page (defaults to 20)
24422 * @cfg {String} displayMsg
24423 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24425 displayMsg : 'Displaying {0} - {1} of {2}',
24427 * @cfg {String} emptyMsg
24428 * The message to display when no records are found (defaults to "No data to display")
24430 emptyMsg : 'No data to display',
24432 * Customizable piece of the default paging text (defaults to "Page")
24435 beforePageText : "Page",
24437 * Customizable piece of the default paging text (defaults to "of %0")
24440 afterPageText : "of {0}",
24442 * Customizable piece of the default paging text (defaults to "First Page")
24445 firstText : "First Page",
24447 * Customizable piece of the default paging text (defaults to "Previous Page")
24450 prevText : "Previous Page",
24452 * Customizable piece of the default paging text (defaults to "Next Page")
24455 nextText : "Next Page",
24457 * Customizable piece of the default paging text (defaults to "Last Page")
24460 lastText : "Last Page",
24462 * Customizable piece of the default paging text (defaults to "Refresh")
24465 refreshText : "Refresh",
24469 onRender : function(ct, position)
24471 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24472 this.navgroup.parentId = this.id;
24473 this.navgroup.onRender(this.el, null);
24474 // add the buttons to the navgroup
24476 if(this.displayInfo){
24477 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24478 this.displayEl = this.el.select('.x-paging-info', true).first();
24479 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24480 // this.displayEl = navel.el.select('span',true).first();
24486 Roo.each(_this.buttons, function(e){ // this might need to use render????
24487 Roo.factory(e).onRender(_this.el, null);
24491 Roo.each(_this.toolbarItems, function(e) {
24492 _this.navgroup.addItem(e);
24496 this.first = this.navgroup.addItem({
24497 tooltip: this.firstText,
24499 icon : 'fa fa-backward',
24501 preventDefault: true,
24502 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24505 this.prev = this.navgroup.addItem({
24506 tooltip: this.prevText,
24508 icon : 'fa fa-step-backward',
24510 preventDefault: true,
24511 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24513 //this.addSeparator();
24516 var field = this.navgroup.addItem( {
24518 cls : 'x-paging-position',
24520 html : this.beforePageText +
24521 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24522 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24525 this.field = field.el.select('input', true).first();
24526 this.field.on("keydown", this.onPagingKeydown, this);
24527 this.field.on("focus", function(){this.dom.select();});
24530 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24531 //this.field.setHeight(18);
24532 //this.addSeparator();
24533 this.next = this.navgroup.addItem({
24534 tooltip: this.nextText,
24536 html : ' <i class="fa fa-step-forward">',
24538 preventDefault: true,
24539 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24541 this.last = this.navgroup.addItem({
24542 tooltip: this.lastText,
24543 icon : 'fa fa-forward',
24546 preventDefault: true,
24547 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24549 //this.addSeparator();
24550 this.loading = this.navgroup.addItem({
24551 tooltip: this.refreshText,
24552 icon: 'fa fa-refresh',
24553 preventDefault: true,
24554 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24560 updateInfo : function(){
24561 if(this.displayEl){
24562 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24563 var msg = count == 0 ?
24567 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24569 this.displayEl.update(msg);
24574 onLoad : function(ds, r, o)
24576 this.cursor = o.params.start ? o.params.start : 0;
24578 var d = this.getPageData(),
24583 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24584 this.field.dom.value = ap;
24585 this.first.setDisabled(ap == 1);
24586 this.prev.setDisabled(ap == 1);
24587 this.next.setDisabled(ap == ps);
24588 this.last.setDisabled(ap == ps);
24589 this.loading.enable();
24594 getPageData : function(){
24595 var total = this.ds.getTotalCount();
24598 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24599 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24604 onLoadError : function(){
24605 this.loading.enable();
24609 onPagingKeydown : function(e){
24610 var k = e.getKey();
24611 var d = this.getPageData();
24613 var v = this.field.dom.value, pageNum;
24614 if(!v || isNaN(pageNum = parseInt(v, 10))){
24615 this.field.dom.value = d.activePage;
24618 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24619 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24622 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))
24624 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24625 this.field.dom.value = pageNum;
24626 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24629 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24631 var v = this.field.dom.value, pageNum;
24632 var increment = (e.shiftKey) ? 10 : 1;
24633 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24636 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24637 this.field.dom.value = d.activePage;
24640 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24642 this.field.dom.value = parseInt(v, 10) + increment;
24643 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24644 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24651 beforeLoad : function(){
24653 this.loading.disable();
24658 onClick : function(which){
24667 ds.load({params:{start: 0, limit: this.pageSize}});
24670 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24673 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24676 var total = ds.getTotalCount();
24677 var extra = total % this.pageSize;
24678 var lastStart = extra ? (total - extra) : total-this.pageSize;
24679 ds.load({params:{start: lastStart, limit: this.pageSize}});
24682 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24688 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24689 * @param {Roo.data.Store} store The data store to unbind
24691 unbind : function(ds){
24692 ds.un("beforeload", this.beforeLoad, this);
24693 ds.un("load", this.onLoad, this);
24694 ds.un("loadexception", this.onLoadError, this);
24695 ds.un("remove", this.updateInfo, this);
24696 ds.un("add", this.updateInfo, this);
24697 this.ds = undefined;
24701 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24702 * @param {Roo.data.Store} store The data store to bind
24704 bind : function(ds){
24705 ds.on("beforeload", this.beforeLoad, this);
24706 ds.on("load", this.onLoad, this);
24707 ds.on("loadexception", this.onLoadError, this);
24708 ds.on("remove", this.updateInfo, this);
24709 ds.on("add", this.updateInfo, this);
24720 * @class Roo.bootstrap.MessageBar
24721 * @extends Roo.bootstrap.Component
24722 * Bootstrap MessageBar class
24723 * @cfg {String} html contents of the MessageBar
24724 * @cfg {String} weight (info | success | warning | danger) default info
24725 * @cfg {String} beforeClass insert the bar before the given class
24726 * @cfg {Boolean} closable (true | false) default false
24727 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24730 * Create a new Element
24731 * @param {Object} config The config object
24734 Roo.bootstrap.MessageBar = function(config){
24735 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24738 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24744 beforeClass: 'bootstrap-sticky-wrap',
24746 getAutoCreate : function(){
24750 cls: 'alert alert-dismissable alert-' + this.weight,
24755 html: this.html || ''
24761 cfg.cls += ' alert-messages-fixed';
24775 onRender : function(ct, position)
24777 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24780 var cfg = Roo.apply({}, this.getAutoCreate());
24784 cfg.cls += ' ' + this.cls;
24787 cfg.style = this.style;
24789 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24791 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24794 this.el.select('>button.close').on('click', this.hide, this);
24800 if (!this.rendered) {
24806 this.fireEvent('show', this);
24812 if (!this.rendered) {
24818 this.fireEvent('hide', this);
24821 update : function()
24823 // var e = this.el.dom.firstChild;
24825 // if(this.closable){
24826 // e = e.nextSibling;
24829 // e.data = this.html || '';
24831 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24847 * @class Roo.bootstrap.Graph
24848 * @extends Roo.bootstrap.Component
24849 * Bootstrap Graph class
24853 @cfg {String} graphtype bar | vbar | pie
24854 @cfg {number} g_x coodinator | centre x (pie)
24855 @cfg {number} g_y coodinator | centre y (pie)
24856 @cfg {number} g_r radius (pie)
24857 @cfg {number} g_height height of the chart (respected by all elements in the set)
24858 @cfg {number} g_width width of the chart (respected by all elements in the set)
24859 @cfg {Object} title The title of the chart
24862 -opts (object) options for the chart
24864 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24865 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24867 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.
24868 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24870 o stretch (boolean)
24872 -opts (object) options for the pie
24875 o startAngle (number)
24876 o endAngle (number)
24880 * Create a new Input
24881 * @param {Object} config The config object
24884 Roo.bootstrap.Graph = function(config){
24885 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24891 * The img click event for the img.
24892 * @param {Roo.EventObject} e
24898 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24909 //g_colors: this.colors,
24916 getAutoCreate : function(){
24927 onRender : function(ct,position){
24930 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24932 if (typeof(Raphael) == 'undefined') {
24933 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24937 this.raphael = Raphael(this.el.dom);
24939 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24940 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24941 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24942 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24944 r.text(160, 10, "Single Series Chart").attr(txtattr);
24945 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24946 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24947 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24949 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24950 r.barchart(330, 10, 300, 220, data1);
24951 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24952 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24955 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24956 // r.barchart(30, 30, 560, 250, xdata, {
24957 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24958 // axis : "0 0 1 1",
24959 // axisxlabels : xdata
24960 // //yvalues : cols,
24963 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24965 // this.load(null,xdata,{
24966 // axis : "0 0 1 1",
24967 // axisxlabels : xdata
24972 load : function(graphtype,xdata,opts)
24974 this.raphael.clear();
24976 graphtype = this.graphtype;
24981 var r = this.raphael,
24982 fin = function () {
24983 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24985 fout = function () {
24986 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24988 pfin = function() {
24989 this.sector.stop();
24990 this.sector.scale(1.1, 1.1, this.cx, this.cy);
24993 this.label[0].stop();
24994 this.label[0].attr({ r: 7.5 });
24995 this.label[1].attr({ "font-weight": 800 });
24998 pfout = function() {
24999 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25002 this.label[0].animate({ r: 5 }, 500, "bounce");
25003 this.label[1].attr({ "font-weight": 400 });
25009 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25012 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25015 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25016 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25018 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25025 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25030 setTitle: function(o)
25035 initEvents: function() {
25038 this.el.on('click', this.onClick, this);
25042 onClick : function(e)
25044 Roo.log('img onclick');
25045 this.fireEvent('click', this, e);
25057 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25060 * @class Roo.bootstrap.dash.NumberBox
25061 * @extends Roo.bootstrap.Component
25062 * Bootstrap NumberBox class
25063 * @cfg {String} headline Box headline
25064 * @cfg {String} content Box content
25065 * @cfg {String} icon Box icon
25066 * @cfg {String} footer Footer text
25067 * @cfg {String} fhref Footer href
25070 * Create a new NumberBox
25071 * @param {Object} config The config object
25075 Roo.bootstrap.dash.NumberBox = function(config){
25076 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25080 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25089 getAutoCreate : function(){
25093 cls : 'small-box ',
25101 cls : 'roo-headline',
25102 html : this.headline
25106 cls : 'roo-content',
25107 html : this.content
25121 cls : 'ion ' + this.icon
25130 cls : 'small-box-footer',
25131 href : this.fhref || '#',
25135 cfg.cn.push(footer);
25142 onRender : function(ct,position){
25143 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25150 setHeadline: function (value)
25152 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25155 setFooter: function (value, href)
25157 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25160 this.el.select('a.small-box-footer',true).first().attr('href', href);
25165 setContent: function (value)
25167 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25170 initEvents: function()
25184 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25187 * @class Roo.bootstrap.dash.TabBox
25188 * @extends Roo.bootstrap.Component
25189 * Bootstrap TabBox class
25190 * @cfg {String} title Title of the TabBox
25191 * @cfg {String} icon Icon of the TabBox
25192 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25193 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25196 * Create a new TabBox
25197 * @param {Object} config The config object
25201 Roo.bootstrap.dash.TabBox = function(config){
25202 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25207 * When a pane is added
25208 * @param {Roo.bootstrap.dash.TabPane} pane
25212 * @event activatepane
25213 * When a pane is activated
25214 * @param {Roo.bootstrap.dash.TabPane} pane
25216 "activatepane" : true
25224 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25229 tabScrollable : false,
25231 getChildContainer : function()
25233 return this.el.select('.tab-content', true).first();
25236 getAutoCreate : function(){
25240 cls: 'pull-left header',
25248 cls: 'fa ' + this.icon
25254 cls: 'nav nav-tabs pull-right',
25260 if(this.tabScrollable){
25267 cls: 'nav nav-tabs pull-right',
25278 cls: 'nav-tabs-custom',
25283 cls: 'tab-content no-padding',
25291 initEvents : function()
25293 //Roo.log('add add pane handler');
25294 this.on('addpane', this.onAddPane, this);
25297 * Updates the box title
25298 * @param {String} html to set the title to.
25300 setTitle : function(value)
25302 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25304 onAddPane : function(pane)
25306 this.panes.push(pane);
25307 //Roo.log('addpane');
25309 // tabs are rendere left to right..
25310 if(!this.showtabs){
25314 var ctr = this.el.select('.nav-tabs', true).first();
25317 var existing = ctr.select('.nav-tab',true);
25318 var qty = existing.getCount();;
25321 var tab = ctr.createChild({
25323 cls : 'nav-tab' + (qty ? '' : ' active'),
25331 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25334 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25336 pane.el.addClass('active');
25341 onTabClick : function(ev,un,ob,pane)
25343 //Roo.log('tab - prev default');
25344 ev.preventDefault();
25347 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25348 pane.tab.addClass('active');
25349 //Roo.log(pane.title);
25350 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25351 // technically we should have a deactivate event.. but maybe add later.
25352 // and it should not de-activate the selected tab...
25353 this.fireEvent('activatepane', pane);
25354 pane.el.addClass('active');
25355 pane.fireEvent('activate');
25360 getActivePane : function()
25363 Roo.each(this.panes, function(p) {
25364 if(p.el.hasClass('active')){
25385 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25387 * @class Roo.bootstrap.TabPane
25388 * @extends Roo.bootstrap.Component
25389 * Bootstrap TabPane class
25390 * @cfg {Boolean} active (false | true) Default false
25391 * @cfg {String} title title of panel
25395 * Create a new TabPane
25396 * @param {Object} config The config object
25399 Roo.bootstrap.dash.TabPane = function(config){
25400 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25406 * When a pane is activated
25407 * @param {Roo.bootstrap.dash.TabPane} pane
25414 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25419 // the tabBox that this is attached to.
25422 getAutoCreate : function()
25430 cfg.cls += ' active';
25435 initEvents : function()
25437 //Roo.log('trigger add pane handler');
25438 this.parent().fireEvent('addpane', this)
25442 * Updates the tab title
25443 * @param {String} html to set the title to.
25445 setTitle: function(str)
25451 this.tab.select('a', true).first().dom.innerHTML = str;
25468 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25471 * @class Roo.bootstrap.menu.Menu
25472 * @extends Roo.bootstrap.Component
25473 * Bootstrap Menu class - container for Menu
25474 * @cfg {String} html Text of the menu
25475 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25476 * @cfg {String} icon Font awesome icon
25477 * @cfg {String} pos Menu align to (top | bottom) default bottom
25481 * Create a new Menu
25482 * @param {Object} config The config object
25486 Roo.bootstrap.menu.Menu = function(config){
25487 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25491 * @event beforeshow
25492 * Fires before this menu is displayed
25493 * @param {Roo.bootstrap.menu.Menu} this
25497 * @event beforehide
25498 * Fires before this menu is hidden
25499 * @param {Roo.bootstrap.menu.Menu} this
25504 * Fires after this menu is displayed
25505 * @param {Roo.bootstrap.menu.Menu} this
25510 * Fires after this menu is hidden
25511 * @param {Roo.bootstrap.menu.Menu} this
25516 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25517 * @param {Roo.bootstrap.menu.Menu} this
25518 * @param {Roo.EventObject} e
25525 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25529 weight : 'default',
25534 getChildContainer : function() {
25535 if(this.isSubMenu){
25539 return this.el.select('ul.dropdown-menu', true).first();
25542 getAutoCreate : function()
25547 cls : 'roo-menu-text',
25555 cls : 'fa ' + this.icon
25566 cls : 'dropdown-button btn btn-' + this.weight,
25571 cls : 'dropdown-toggle btn btn-' + this.weight,
25581 cls : 'dropdown-menu'
25587 if(this.pos == 'top'){
25588 cfg.cls += ' dropup';
25591 if(this.isSubMenu){
25594 cls : 'dropdown-menu'
25601 onRender : function(ct, position)
25603 this.isSubMenu = ct.hasClass('dropdown-submenu');
25605 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25608 initEvents : function()
25610 if(this.isSubMenu){
25614 this.hidden = true;
25616 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25617 this.triggerEl.on('click', this.onTriggerPress, this);
25619 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25620 this.buttonEl.on('click', this.onClick, this);
25626 if(this.isSubMenu){
25630 return this.el.select('ul.dropdown-menu', true).first();
25633 onClick : function(e)
25635 this.fireEvent("click", this, e);
25638 onTriggerPress : function(e)
25640 if (this.isVisible()) {
25647 isVisible : function(){
25648 return !this.hidden;
25653 this.fireEvent("beforeshow", this);
25655 this.hidden = false;
25656 this.el.addClass('open');
25658 Roo.get(document).on("mouseup", this.onMouseUp, this);
25660 this.fireEvent("show", this);
25667 this.fireEvent("beforehide", this);
25669 this.hidden = true;
25670 this.el.removeClass('open');
25672 Roo.get(document).un("mouseup", this.onMouseUp);
25674 this.fireEvent("hide", this);
25677 onMouseUp : function()
25691 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25694 * @class Roo.bootstrap.menu.Item
25695 * @extends Roo.bootstrap.Component
25696 * Bootstrap MenuItem class
25697 * @cfg {Boolean} submenu (true | false) default false
25698 * @cfg {String} html text of the item
25699 * @cfg {String} href the link
25700 * @cfg {Boolean} disable (true | false) default false
25701 * @cfg {Boolean} preventDefault (true | false) default true
25702 * @cfg {String} icon Font awesome icon
25703 * @cfg {String} pos Submenu align to (left | right) default right
25707 * Create a new Item
25708 * @param {Object} config The config object
25712 Roo.bootstrap.menu.Item = function(config){
25713 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25717 * Fires when the mouse is hovering over this menu
25718 * @param {Roo.bootstrap.menu.Item} this
25719 * @param {Roo.EventObject} e
25724 * Fires when the mouse exits this menu
25725 * @param {Roo.bootstrap.menu.Item} this
25726 * @param {Roo.EventObject} e
25732 * The raw click event for the entire grid.
25733 * @param {Roo.EventObject} e
25739 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25744 preventDefault: true,
25749 getAutoCreate : function()
25754 cls : 'roo-menu-item-text',
25762 cls : 'fa ' + this.icon
25771 href : this.href || '#',
25778 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25782 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25784 if(this.pos == 'left'){
25785 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25792 initEvents : function()
25794 this.el.on('mouseover', this.onMouseOver, this);
25795 this.el.on('mouseout', this.onMouseOut, this);
25797 this.el.select('a', true).first().on('click', this.onClick, this);
25801 onClick : function(e)
25803 if(this.preventDefault){
25804 e.preventDefault();
25807 this.fireEvent("click", this, e);
25810 onMouseOver : function(e)
25812 if(this.submenu && this.pos == 'left'){
25813 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25816 this.fireEvent("mouseover", this, e);
25819 onMouseOut : function(e)
25821 this.fireEvent("mouseout", this, e);
25833 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25836 * @class Roo.bootstrap.menu.Separator
25837 * @extends Roo.bootstrap.Component
25838 * Bootstrap Separator class
25841 * Create a new Separator
25842 * @param {Object} config The config object
25846 Roo.bootstrap.menu.Separator = function(config){
25847 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25850 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25852 getAutoCreate : function(){
25873 * @class Roo.bootstrap.Tooltip
25874 * Bootstrap Tooltip class
25875 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25876 * to determine which dom element triggers the tooltip.
25878 * It needs to add support for additional attributes like tooltip-position
25881 * Create a new Toolti
25882 * @param {Object} config The config object
25885 Roo.bootstrap.Tooltip = function(config){
25886 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25888 this.alignment = Roo.bootstrap.Tooltip.alignment;
25890 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25891 this.alignment = config.alignment;
25896 Roo.apply(Roo.bootstrap.Tooltip, {
25898 * @function init initialize tooltip monitoring.
25902 currentTip : false,
25903 currentRegion : false,
25909 Roo.get(document).on('mouseover', this.enter ,this);
25910 Roo.get(document).on('mouseout', this.leave, this);
25913 this.currentTip = new Roo.bootstrap.Tooltip();
25916 enter : function(ev)
25918 var dom = ev.getTarget();
25920 //Roo.log(['enter',dom]);
25921 var el = Roo.fly(dom);
25922 if (this.currentEl) {
25924 //Roo.log(this.currentEl);
25925 //Roo.log(this.currentEl.contains(dom));
25926 if (this.currentEl == el) {
25929 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25935 if (this.currentTip.el) {
25936 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25940 if(!el || el.dom == document){
25946 // you can not look for children, as if el is the body.. then everythign is the child..
25947 if (!el.attr('tooltip')) { //
25948 if (!el.select("[tooltip]").elements.length) {
25951 // is the mouse over this child...?
25952 bindEl = el.select("[tooltip]").first();
25953 var xy = ev.getXY();
25954 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25955 //Roo.log("not in region.");
25958 //Roo.log("child element over..");
25961 this.currentEl = bindEl;
25962 this.currentTip.bind(bindEl);
25963 this.currentRegion = Roo.lib.Region.getRegion(dom);
25964 this.currentTip.enter();
25967 leave : function(ev)
25969 var dom = ev.getTarget();
25970 //Roo.log(['leave',dom]);
25971 if (!this.currentEl) {
25976 if (dom != this.currentEl.dom) {
25979 var xy = ev.getXY();
25980 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25983 // only activate leave if mouse cursor is outside... bounding box..
25988 if (this.currentTip) {
25989 this.currentTip.leave();
25991 //Roo.log('clear currentEl');
25992 this.currentEl = false;
25997 'left' : ['r-l', [-2,0], 'right'],
25998 'right' : ['l-r', [2,0], 'left'],
25999 'bottom' : ['t-b', [0,2], 'top'],
26000 'top' : [ 'b-t', [0,-2], 'bottom']
26006 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26011 delay : null, // can be { show : 300 , hide: 500}
26015 hoverState : null, //???
26017 placement : 'bottom',
26021 getAutoCreate : function(){
26028 cls : 'tooltip-arrow'
26031 cls : 'tooltip-inner'
26038 bind : function(el)
26044 enter : function () {
26046 if (this.timeout != null) {
26047 clearTimeout(this.timeout);
26050 this.hoverState = 'in';
26051 //Roo.log("enter - show");
26052 if (!this.delay || !this.delay.show) {
26057 this.timeout = setTimeout(function () {
26058 if (_t.hoverState == 'in') {
26061 }, this.delay.show);
26065 clearTimeout(this.timeout);
26067 this.hoverState = 'out';
26068 if (!this.delay || !this.delay.hide) {
26074 this.timeout = setTimeout(function () {
26075 //Roo.log("leave - timeout");
26077 if (_t.hoverState == 'out') {
26079 Roo.bootstrap.Tooltip.currentEl = false;
26084 show : function (msg)
26087 this.render(document.body);
26090 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26092 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26094 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26096 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26098 var placement = typeof this.placement == 'function' ?
26099 this.placement.call(this, this.el, on_el) :
26102 var autoToken = /\s?auto?\s?/i;
26103 var autoPlace = autoToken.test(placement);
26105 placement = placement.replace(autoToken, '') || 'top';
26109 //this.el.setXY([0,0]);
26111 //this.el.dom.style.display='block';
26113 //this.el.appendTo(on_el);
26115 var p = this.getPosition();
26116 var box = this.el.getBox();
26122 var align = this.alignment[placement];
26124 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26126 if(placement == 'top' || placement == 'bottom'){
26128 placement = 'right';
26131 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26132 placement = 'left';
26135 var scroll = Roo.select('body', true).first().getScroll();
26137 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26143 this.el.alignTo(this.bindEl, align[0],align[1]);
26144 //var arrow = this.el.select('.arrow',true).first();
26145 //arrow.set(align[2],
26147 this.el.addClass(placement);
26149 this.el.addClass('in fade');
26151 this.hoverState = null;
26153 if (this.el.hasClass('fade')) {
26164 //this.el.setXY([0,0]);
26165 this.el.removeClass('in');
26181 * @class Roo.bootstrap.LocationPicker
26182 * @extends Roo.bootstrap.Component
26183 * Bootstrap LocationPicker class
26184 * @cfg {Number} latitude Position when init default 0
26185 * @cfg {Number} longitude Position when init default 0
26186 * @cfg {Number} zoom default 15
26187 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26188 * @cfg {Boolean} mapTypeControl default false
26189 * @cfg {Boolean} disableDoubleClickZoom default false
26190 * @cfg {Boolean} scrollwheel default true
26191 * @cfg {Boolean} streetViewControl default false
26192 * @cfg {Number} radius default 0
26193 * @cfg {String} locationName
26194 * @cfg {Boolean} draggable default true
26195 * @cfg {Boolean} enableAutocomplete default false
26196 * @cfg {Boolean} enableReverseGeocode default true
26197 * @cfg {String} markerTitle
26200 * Create a new LocationPicker
26201 * @param {Object} config The config object
26205 Roo.bootstrap.LocationPicker = function(config){
26207 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26212 * Fires when the picker initialized.
26213 * @param {Roo.bootstrap.LocationPicker} this
26214 * @param {Google Location} location
26218 * @event positionchanged
26219 * Fires when the picker position changed.
26220 * @param {Roo.bootstrap.LocationPicker} this
26221 * @param {Google Location} location
26223 positionchanged : true,
26226 * Fires when the map resize.
26227 * @param {Roo.bootstrap.LocationPicker} this
26232 * Fires when the map show.
26233 * @param {Roo.bootstrap.LocationPicker} this
26238 * Fires when the map hide.
26239 * @param {Roo.bootstrap.LocationPicker} this
26244 * Fires when click the map.
26245 * @param {Roo.bootstrap.LocationPicker} this
26246 * @param {Map event} e
26250 * @event mapRightClick
26251 * Fires when right click the map.
26252 * @param {Roo.bootstrap.LocationPicker} this
26253 * @param {Map event} e
26255 mapRightClick : true,
26257 * @event markerClick
26258 * Fires when click the marker.
26259 * @param {Roo.bootstrap.LocationPicker} this
26260 * @param {Map event} e
26262 markerClick : true,
26264 * @event markerRightClick
26265 * Fires when right click the marker.
26266 * @param {Roo.bootstrap.LocationPicker} this
26267 * @param {Map event} e
26269 markerRightClick : true,
26271 * @event OverlayViewDraw
26272 * Fires when OverlayView Draw
26273 * @param {Roo.bootstrap.LocationPicker} this
26275 OverlayViewDraw : true,
26277 * @event OverlayViewOnAdd
26278 * Fires when OverlayView Draw
26279 * @param {Roo.bootstrap.LocationPicker} this
26281 OverlayViewOnAdd : true,
26283 * @event OverlayViewOnRemove
26284 * Fires when OverlayView Draw
26285 * @param {Roo.bootstrap.LocationPicker} this
26287 OverlayViewOnRemove : true,
26289 * @event OverlayViewShow
26290 * Fires when OverlayView Draw
26291 * @param {Roo.bootstrap.LocationPicker} this
26292 * @param {Pixel} cpx
26294 OverlayViewShow : true,
26296 * @event OverlayViewHide
26297 * Fires when OverlayView Draw
26298 * @param {Roo.bootstrap.LocationPicker} this
26300 OverlayViewHide : true,
26302 * @event loadexception
26303 * Fires when load google lib failed.
26304 * @param {Roo.bootstrap.LocationPicker} this
26306 loadexception : true
26311 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26313 gMapContext: false,
26319 mapTypeControl: false,
26320 disableDoubleClickZoom: false,
26322 streetViewControl: false,
26326 enableAutocomplete: false,
26327 enableReverseGeocode: true,
26330 getAutoCreate: function()
26335 cls: 'roo-location-picker'
26341 initEvents: function(ct, position)
26343 if(!this.el.getWidth() || this.isApplied()){
26347 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26352 initial: function()
26354 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26355 this.fireEvent('loadexception', this);
26359 if(!this.mapTypeId){
26360 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26363 this.gMapContext = this.GMapContext();
26365 this.initOverlayView();
26367 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26371 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26372 _this.setPosition(_this.gMapContext.marker.position);
26375 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26376 _this.fireEvent('mapClick', this, event);
26380 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26381 _this.fireEvent('mapRightClick', this, event);
26385 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26386 _this.fireEvent('markerClick', this, event);
26390 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26391 _this.fireEvent('markerRightClick', this, event);
26395 this.setPosition(this.gMapContext.location);
26397 this.fireEvent('initial', this, this.gMapContext.location);
26400 initOverlayView: function()
26404 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26408 _this.fireEvent('OverlayViewDraw', _this);
26413 _this.fireEvent('OverlayViewOnAdd', _this);
26416 onRemove: function()
26418 _this.fireEvent('OverlayViewOnRemove', _this);
26421 show: function(cpx)
26423 _this.fireEvent('OverlayViewShow', _this, cpx);
26428 _this.fireEvent('OverlayViewHide', _this);
26434 fromLatLngToContainerPixel: function(event)
26436 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26439 isApplied: function()
26441 return this.getGmapContext() == false ? false : true;
26444 getGmapContext: function()
26446 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26449 GMapContext: function()
26451 var position = new google.maps.LatLng(this.latitude, this.longitude);
26453 var _map = new google.maps.Map(this.el.dom, {
26456 mapTypeId: this.mapTypeId,
26457 mapTypeControl: this.mapTypeControl,
26458 disableDoubleClickZoom: this.disableDoubleClickZoom,
26459 scrollwheel: this.scrollwheel,
26460 streetViewControl: this.streetViewControl,
26461 locationName: this.locationName,
26462 draggable: this.draggable,
26463 enableAutocomplete: this.enableAutocomplete,
26464 enableReverseGeocode: this.enableReverseGeocode
26467 var _marker = new google.maps.Marker({
26468 position: position,
26470 title: this.markerTitle,
26471 draggable: this.draggable
26478 location: position,
26479 radius: this.radius,
26480 locationName: this.locationName,
26481 addressComponents: {
26482 formatted_address: null,
26483 addressLine1: null,
26484 addressLine2: null,
26486 streetNumber: null,
26490 stateOrProvince: null
26493 domContainer: this.el.dom,
26494 geodecoder: new google.maps.Geocoder()
26498 drawCircle: function(center, radius, options)
26500 if (this.gMapContext.circle != null) {
26501 this.gMapContext.circle.setMap(null);
26505 options = Roo.apply({}, options, {
26506 strokeColor: "#0000FF",
26507 strokeOpacity: .35,
26509 fillColor: "#0000FF",
26513 options.map = this.gMapContext.map;
26514 options.radius = radius;
26515 options.center = center;
26516 this.gMapContext.circle = new google.maps.Circle(options);
26517 return this.gMapContext.circle;
26523 setPosition: function(location)
26525 this.gMapContext.location = location;
26526 this.gMapContext.marker.setPosition(location);
26527 this.gMapContext.map.panTo(location);
26528 this.drawCircle(location, this.gMapContext.radius, {});
26532 if (this.gMapContext.settings.enableReverseGeocode) {
26533 this.gMapContext.geodecoder.geocode({
26534 latLng: this.gMapContext.location
26535 }, function(results, status) {
26537 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26538 _this.gMapContext.locationName = results[0].formatted_address;
26539 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26541 _this.fireEvent('positionchanged', this, location);
26548 this.fireEvent('positionchanged', this, location);
26553 google.maps.event.trigger(this.gMapContext.map, "resize");
26555 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26557 this.fireEvent('resize', this);
26560 setPositionByLatLng: function(latitude, longitude)
26562 this.setPosition(new google.maps.LatLng(latitude, longitude));
26565 getCurrentPosition: function()
26568 latitude: this.gMapContext.location.lat(),
26569 longitude: this.gMapContext.location.lng()
26573 getAddressName: function()
26575 return this.gMapContext.locationName;
26578 getAddressComponents: function()
26580 return this.gMapContext.addressComponents;
26583 address_component_from_google_geocode: function(address_components)
26587 for (var i = 0; i < address_components.length; i++) {
26588 var component = address_components[i];
26589 if (component.types.indexOf("postal_code") >= 0) {
26590 result.postalCode = component.short_name;
26591 } else if (component.types.indexOf("street_number") >= 0) {
26592 result.streetNumber = component.short_name;
26593 } else if (component.types.indexOf("route") >= 0) {
26594 result.streetName = component.short_name;
26595 } else if (component.types.indexOf("neighborhood") >= 0) {
26596 result.city = component.short_name;
26597 } else if (component.types.indexOf("locality") >= 0) {
26598 result.city = component.short_name;
26599 } else if (component.types.indexOf("sublocality") >= 0) {
26600 result.district = component.short_name;
26601 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26602 result.stateOrProvince = component.short_name;
26603 } else if (component.types.indexOf("country") >= 0) {
26604 result.country = component.short_name;
26608 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26609 result.addressLine2 = "";
26613 setZoomLevel: function(zoom)
26615 this.gMapContext.map.setZoom(zoom);
26628 this.fireEvent('show', this);
26639 this.fireEvent('hide', this);
26644 Roo.apply(Roo.bootstrap.LocationPicker, {
26646 OverlayView : function(map, options)
26648 options = options || {};
26662 * @class Roo.bootstrap.Alert
26663 * @extends Roo.bootstrap.Component
26664 * Bootstrap Alert class
26665 * @cfg {String} title The title of alert
26666 * @cfg {String} html The content of alert
26667 * @cfg {String} weight ( success | info | warning | danger )
26668 * @cfg {String} faicon font-awesomeicon
26671 * Create a new alert
26672 * @param {Object} config The config object
26676 Roo.bootstrap.Alert = function(config){
26677 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26681 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26688 getAutoCreate : function()
26697 cls : 'roo-alert-icon'
26702 cls : 'roo-alert-title',
26707 cls : 'roo-alert-text',
26714 cfg.cn[0].cls += ' fa ' + this.faicon;
26718 cfg.cls += ' alert-' + this.weight;
26724 initEvents: function()
26726 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26729 setTitle : function(str)
26731 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26734 setText : function(str)
26736 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26739 setWeight : function(weight)
26742 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26745 this.weight = weight;
26747 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26750 setIcon : function(icon)
26753 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26756 this.faicon = icon;
26758 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26779 * @class Roo.bootstrap.UploadCropbox
26780 * @extends Roo.bootstrap.Component
26781 * Bootstrap UploadCropbox class
26782 * @cfg {String} emptyText show when image has been loaded
26783 * @cfg {String} rotateNotify show when image too small to rotate
26784 * @cfg {Number} errorTimeout default 3000
26785 * @cfg {Number} minWidth default 300
26786 * @cfg {Number} minHeight default 300
26787 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26788 * @cfg {Boolean} isDocument (true|false) default false
26789 * @cfg {String} url action url
26790 * @cfg {String} paramName default 'imageUpload'
26791 * @cfg {String} method default POST
26792 * @cfg {Boolean} loadMask (true|false) default true
26793 * @cfg {Boolean} loadingText default 'Loading...'
26796 * Create a new UploadCropbox
26797 * @param {Object} config The config object
26800 Roo.bootstrap.UploadCropbox = function(config){
26801 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26805 * @event beforeselectfile
26806 * Fire before select file
26807 * @param {Roo.bootstrap.UploadCropbox} this
26809 "beforeselectfile" : true,
26812 * Fire after initEvent
26813 * @param {Roo.bootstrap.UploadCropbox} this
26818 * Fire after initEvent
26819 * @param {Roo.bootstrap.UploadCropbox} this
26820 * @param {String} data
26825 * Fire when preparing the file data
26826 * @param {Roo.bootstrap.UploadCropbox} this
26827 * @param {Object} file
26832 * Fire when get exception
26833 * @param {Roo.bootstrap.UploadCropbox} this
26834 * @param {XMLHttpRequest} xhr
26836 "exception" : true,
26838 * @event beforeloadcanvas
26839 * Fire before load the canvas
26840 * @param {Roo.bootstrap.UploadCropbox} this
26841 * @param {String} src
26843 "beforeloadcanvas" : true,
26846 * Fire when trash image
26847 * @param {Roo.bootstrap.UploadCropbox} this
26852 * Fire when download the image
26853 * @param {Roo.bootstrap.UploadCropbox} this
26857 * @event footerbuttonclick
26858 * Fire when footerbuttonclick
26859 * @param {Roo.bootstrap.UploadCropbox} this
26860 * @param {String} type
26862 "footerbuttonclick" : true,
26866 * @param {Roo.bootstrap.UploadCropbox} this
26871 * Fire when rotate the image
26872 * @param {Roo.bootstrap.UploadCropbox} this
26873 * @param {String} pos
26878 * Fire when inspect the file
26879 * @param {Roo.bootstrap.UploadCropbox} this
26880 * @param {Object} file
26885 * Fire when xhr upload the file
26886 * @param {Roo.bootstrap.UploadCropbox} this
26887 * @param {Object} data
26892 * Fire when arrange the file data
26893 * @param {Roo.bootstrap.UploadCropbox} this
26894 * @param {Object} formData
26899 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26902 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26904 emptyText : 'Click to upload image',
26905 rotateNotify : 'Image is too small to rotate',
26906 errorTimeout : 3000,
26920 cropType : 'image/jpeg',
26922 canvasLoaded : false,
26923 isDocument : false,
26925 paramName : 'imageUpload',
26927 loadingText : 'Loading...',
26930 getAutoCreate : function()
26934 cls : 'roo-upload-cropbox',
26938 cls : 'roo-upload-cropbox-selector',
26943 cls : 'roo-upload-cropbox-body',
26944 style : 'cursor:pointer',
26948 cls : 'roo-upload-cropbox-preview'
26952 cls : 'roo-upload-cropbox-thumb'
26956 cls : 'roo-upload-cropbox-empty-notify',
26957 html : this.emptyText
26961 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26962 html : this.rotateNotify
26968 cls : 'roo-upload-cropbox-footer',
26971 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26981 onRender : function(ct, position)
26983 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26985 if (this.buttons.length) {
26987 Roo.each(this.buttons, function(bb) {
26989 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
26991 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
26997 this.maskEl = this.el;
27001 initEvents : function()
27003 this.urlAPI = (window.createObjectURL && window) ||
27004 (window.URL && URL.revokeObjectURL && URL) ||
27005 (window.webkitURL && webkitURL);
27007 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27008 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27010 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27011 this.selectorEl.hide();
27013 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27014 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27016 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27017 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27018 this.thumbEl.hide();
27020 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27021 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27023 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27024 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27025 this.errorEl.hide();
27027 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27028 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27029 this.footerEl.hide();
27031 this.setThumbBoxSize();
27037 this.fireEvent('initial', this);
27044 window.addEventListener("resize", function() { _this.resize(); } );
27046 this.bodyEl.on('click', this.beforeSelectFile, this);
27049 this.bodyEl.on('touchstart', this.onTouchStart, this);
27050 this.bodyEl.on('touchmove', this.onTouchMove, this);
27051 this.bodyEl.on('touchend', this.onTouchEnd, this);
27055 this.bodyEl.on('mousedown', this.onMouseDown, this);
27056 this.bodyEl.on('mousemove', this.onMouseMove, this);
27057 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27058 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27059 Roo.get(document).on('mouseup', this.onMouseUp, this);
27062 this.selectorEl.on('change', this.onFileSelected, this);
27068 this.baseScale = 1;
27070 this.baseRotate = 1;
27071 this.dragable = false;
27072 this.pinching = false;
27075 this.cropData = false;
27076 this.notifyEl.dom.innerHTML = this.emptyText;
27078 this.selectorEl.dom.value = '';
27082 resize : function()
27084 if(this.fireEvent('resize', this) != false){
27085 this.setThumbBoxPosition();
27086 this.setCanvasPosition();
27090 onFooterButtonClick : function(e, el, o, type)
27093 case 'rotate-left' :
27094 this.onRotateLeft(e);
27096 case 'rotate-right' :
27097 this.onRotateRight(e);
27100 this.beforeSelectFile(e);
27115 this.fireEvent('footerbuttonclick', this, type);
27118 beforeSelectFile : function(e)
27120 e.preventDefault();
27122 if(this.fireEvent('beforeselectfile', this) != false){
27123 this.selectorEl.dom.click();
27127 onFileSelected : function(e)
27129 e.preventDefault();
27131 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27135 var file = this.selectorEl.dom.files[0];
27137 if(this.fireEvent('inspect', this, file) != false){
27138 this.prepare(file);
27143 trash : function(e)
27145 this.fireEvent('trash', this);
27148 download : function(e)
27150 this.fireEvent('download', this);
27153 loadCanvas : function(src)
27155 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27159 this.imageEl = document.createElement('img');
27163 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27165 this.imageEl.src = src;
27169 onLoadCanvas : function()
27171 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27172 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27174 this.bodyEl.un('click', this.beforeSelectFile, this);
27176 this.notifyEl.hide();
27177 this.thumbEl.show();
27178 this.footerEl.show();
27180 this.baseRotateLevel();
27182 if(this.isDocument){
27183 this.setThumbBoxSize();
27186 this.setThumbBoxPosition();
27188 this.baseScaleLevel();
27194 this.canvasLoaded = true;
27197 this.maskEl.unmask();
27202 setCanvasPosition : function()
27204 if(!this.canvasEl){
27208 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27209 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27211 this.previewEl.setLeft(pw);
27212 this.previewEl.setTop(ph);
27216 onMouseDown : function(e)
27220 this.dragable = true;
27221 this.pinching = false;
27223 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27224 this.dragable = false;
27228 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27229 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27233 onMouseMove : function(e)
27237 if(!this.canvasLoaded){
27241 if (!this.dragable){
27245 var minX = Math.ceil(this.thumbEl.getLeft(true));
27246 var minY = Math.ceil(this.thumbEl.getTop(true));
27248 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27249 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27251 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27252 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27254 x = x - this.mouseX;
27255 y = y - this.mouseY;
27257 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27258 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27260 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27261 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27263 this.previewEl.setLeft(bgX);
27264 this.previewEl.setTop(bgY);
27266 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27267 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27270 onMouseUp : function(e)
27274 this.dragable = false;
27277 onMouseWheel : function(e)
27281 this.startScale = this.scale;
27283 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27285 if(!this.zoomable()){
27286 this.scale = this.startScale;
27295 zoomable : function()
27297 var minScale = this.thumbEl.getWidth() / this.minWidth;
27299 if(this.minWidth < this.minHeight){
27300 minScale = this.thumbEl.getHeight() / this.minHeight;
27303 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27304 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27308 (this.rotate == 0 || this.rotate == 180) &&
27310 width > this.imageEl.OriginWidth ||
27311 height > this.imageEl.OriginHeight ||
27312 (width < this.minWidth && height < this.minHeight)
27320 (this.rotate == 90 || this.rotate == 270) &&
27322 width > this.imageEl.OriginWidth ||
27323 height > this.imageEl.OriginHeight ||
27324 (width < this.minHeight && height < this.minWidth)
27331 !this.isDocument &&
27332 (this.rotate == 0 || this.rotate == 180) &&
27334 width < this.minWidth ||
27335 width > this.imageEl.OriginWidth ||
27336 height < this.minHeight ||
27337 height > this.imageEl.OriginHeight
27344 !this.isDocument &&
27345 (this.rotate == 90 || this.rotate == 270) &&
27347 width < this.minHeight ||
27348 width > this.imageEl.OriginWidth ||
27349 height < this.minWidth ||
27350 height > this.imageEl.OriginHeight
27360 onRotateLeft : function(e)
27362 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27364 var minScale = this.thumbEl.getWidth() / this.minWidth;
27366 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27367 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27369 this.startScale = this.scale;
27371 while (this.getScaleLevel() < minScale){
27373 this.scale = this.scale + 1;
27375 if(!this.zoomable()){
27380 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27381 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27386 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27393 this.scale = this.startScale;
27395 this.onRotateFail();
27400 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27402 if(this.isDocument){
27403 this.setThumbBoxSize();
27404 this.setThumbBoxPosition();
27405 this.setCanvasPosition();
27410 this.fireEvent('rotate', this, 'left');
27414 onRotateRight : function(e)
27416 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27418 var minScale = this.thumbEl.getWidth() / this.minWidth;
27420 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27421 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27423 this.startScale = this.scale;
27425 while (this.getScaleLevel() < minScale){
27427 this.scale = this.scale + 1;
27429 if(!this.zoomable()){
27434 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27435 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27440 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27447 this.scale = this.startScale;
27449 this.onRotateFail();
27454 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27456 if(this.isDocument){
27457 this.setThumbBoxSize();
27458 this.setThumbBoxPosition();
27459 this.setCanvasPosition();
27464 this.fireEvent('rotate', this, 'right');
27467 onRotateFail : function()
27469 this.errorEl.show(true);
27473 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27478 this.previewEl.dom.innerHTML = '';
27480 var canvasEl = document.createElement("canvas");
27482 var contextEl = canvasEl.getContext("2d");
27484 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27485 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27486 var center = this.imageEl.OriginWidth / 2;
27488 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27489 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27490 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27491 center = this.imageEl.OriginHeight / 2;
27494 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27496 contextEl.translate(center, center);
27497 contextEl.rotate(this.rotate * Math.PI / 180);
27499 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27501 this.canvasEl = document.createElement("canvas");
27503 this.contextEl = this.canvasEl.getContext("2d");
27505 switch (this.rotate) {
27508 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27509 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27511 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27516 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27517 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27519 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27520 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27524 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27529 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27530 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27532 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27533 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27537 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27542 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27543 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27545 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27546 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27550 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27557 this.previewEl.appendChild(this.canvasEl);
27559 this.setCanvasPosition();
27564 if(!this.canvasLoaded){
27568 var imageCanvas = document.createElement("canvas");
27570 var imageContext = imageCanvas.getContext("2d");
27572 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27573 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27575 var center = imageCanvas.width / 2;
27577 imageContext.translate(center, center);
27579 imageContext.rotate(this.rotate * Math.PI / 180);
27581 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27583 var canvas = document.createElement("canvas");
27585 var context = canvas.getContext("2d");
27587 canvas.width = this.minWidth;
27588 canvas.height = this.minHeight;
27590 switch (this.rotate) {
27593 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27594 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27596 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27597 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27599 var targetWidth = this.minWidth - 2 * x;
27600 var targetHeight = this.minHeight - 2 * y;
27604 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27605 scale = targetWidth / width;
27608 if(x > 0 && y == 0){
27609 scale = targetHeight / height;
27612 if(x > 0 && y > 0){
27613 scale = targetWidth / width;
27615 if(width < height){
27616 scale = targetHeight / height;
27620 context.scale(scale, scale);
27622 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27623 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27625 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27626 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27628 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27633 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27634 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27636 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27637 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27639 var targetWidth = this.minWidth - 2 * x;
27640 var targetHeight = this.minHeight - 2 * y;
27644 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27645 scale = targetWidth / width;
27648 if(x > 0 && y == 0){
27649 scale = targetHeight / height;
27652 if(x > 0 && y > 0){
27653 scale = targetWidth / width;
27655 if(width < height){
27656 scale = targetHeight / height;
27660 context.scale(scale, scale);
27662 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27663 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27665 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27666 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27668 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27670 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27675 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27676 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27678 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27679 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27681 var targetWidth = this.minWidth - 2 * x;
27682 var targetHeight = this.minHeight - 2 * y;
27686 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27687 scale = targetWidth / width;
27690 if(x > 0 && y == 0){
27691 scale = targetHeight / height;
27694 if(x > 0 && y > 0){
27695 scale = targetWidth / width;
27697 if(width < height){
27698 scale = targetHeight / height;
27702 context.scale(scale, scale);
27704 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27705 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27707 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27708 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27710 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27711 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27713 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27718 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27719 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27721 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27722 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27724 var targetWidth = this.minWidth - 2 * x;
27725 var targetHeight = this.minHeight - 2 * y;
27729 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27730 scale = targetWidth / width;
27733 if(x > 0 && y == 0){
27734 scale = targetHeight / height;
27737 if(x > 0 && y > 0){
27738 scale = targetWidth / width;
27740 if(width < height){
27741 scale = targetHeight / height;
27745 context.scale(scale, scale);
27747 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27748 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27750 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27751 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27753 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27755 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27762 this.cropData = canvas.toDataURL(this.cropType);
27764 if(this.fireEvent('crop', this, this.cropData) !== false){
27765 this.process(this.file, this.cropData);
27772 setThumbBoxSize : function()
27776 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27777 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27778 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27780 this.minWidth = width;
27781 this.minHeight = height;
27783 if(this.rotate == 90 || this.rotate == 270){
27784 this.minWidth = height;
27785 this.minHeight = width;
27790 width = Math.ceil(this.minWidth * height / this.minHeight);
27792 if(this.minWidth > this.minHeight){
27794 height = Math.ceil(this.minHeight * width / this.minWidth);
27797 this.thumbEl.setStyle({
27798 width : width + 'px',
27799 height : height + 'px'
27806 setThumbBoxPosition : function()
27808 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27809 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27811 this.thumbEl.setLeft(x);
27812 this.thumbEl.setTop(y);
27816 baseRotateLevel : function()
27818 this.baseRotate = 1;
27821 typeof(this.exif) != 'undefined' &&
27822 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27823 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27825 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27828 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27832 baseScaleLevel : function()
27836 if(this.isDocument){
27838 if(this.baseRotate == 6 || this.baseRotate == 8){
27840 height = this.thumbEl.getHeight();
27841 this.baseScale = height / this.imageEl.OriginWidth;
27843 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27844 width = this.thumbEl.getWidth();
27845 this.baseScale = width / this.imageEl.OriginHeight;
27851 height = this.thumbEl.getHeight();
27852 this.baseScale = height / this.imageEl.OriginHeight;
27854 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27855 width = this.thumbEl.getWidth();
27856 this.baseScale = width / this.imageEl.OriginWidth;
27862 if(this.baseRotate == 6 || this.baseRotate == 8){
27864 width = this.thumbEl.getHeight();
27865 this.baseScale = width / this.imageEl.OriginHeight;
27867 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27868 height = this.thumbEl.getWidth();
27869 this.baseScale = height / this.imageEl.OriginHeight;
27872 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27873 height = this.thumbEl.getWidth();
27874 this.baseScale = height / this.imageEl.OriginHeight;
27876 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27877 width = this.thumbEl.getHeight();
27878 this.baseScale = width / this.imageEl.OriginWidth;
27885 width = this.thumbEl.getWidth();
27886 this.baseScale = width / this.imageEl.OriginWidth;
27888 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27889 height = this.thumbEl.getHeight();
27890 this.baseScale = height / this.imageEl.OriginHeight;
27893 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27895 height = this.thumbEl.getHeight();
27896 this.baseScale = height / this.imageEl.OriginHeight;
27898 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27899 width = this.thumbEl.getWidth();
27900 this.baseScale = width / this.imageEl.OriginWidth;
27908 getScaleLevel : function()
27910 return this.baseScale * Math.pow(1.1, this.scale);
27913 onTouchStart : function(e)
27915 if(!this.canvasLoaded){
27916 this.beforeSelectFile(e);
27920 var touches = e.browserEvent.touches;
27926 if(touches.length == 1){
27927 this.onMouseDown(e);
27931 if(touches.length != 2){
27937 for(var i = 0, finger; finger = touches[i]; i++){
27938 coords.push(finger.pageX, finger.pageY);
27941 var x = Math.pow(coords[0] - coords[2], 2);
27942 var y = Math.pow(coords[1] - coords[3], 2);
27944 this.startDistance = Math.sqrt(x + y);
27946 this.startScale = this.scale;
27948 this.pinching = true;
27949 this.dragable = false;
27953 onTouchMove : function(e)
27955 if(!this.pinching && !this.dragable){
27959 var touches = e.browserEvent.touches;
27966 this.onMouseMove(e);
27972 for(var i = 0, finger; finger = touches[i]; i++){
27973 coords.push(finger.pageX, finger.pageY);
27976 var x = Math.pow(coords[0] - coords[2], 2);
27977 var y = Math.pow(coords[1] - coords[3], 2);
27979 this.endDistance = Math.sqrt(x + y);
27981 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27983 if(!this.zoomable()){
27984 this.scale = this.startScale;
27992 onTouchEnd : function(e)
27994 this.pinching = false;
27995 this.dragable = false;
27999 process : function(file, crop)
28002 this.maskEl.mask(this.loadingText);
28005 this.xhr = new XMLHttpRequest();
28007 file.xhr = this.xhr;
28009 this.xhr.open(this.method, this.url, true);
28012 "Accept": "application/json",
28013 "Cache-Control": "no-cache",
28014 "X-Requested-With": "XMLHttpRequest"
28017 for (var headerName in headers) {
28018 var headerValue = headers[headerName];
28020 this.xhr.setRequestHeader(headerName, headerValue);
28026 this.xhr.onload = function()
28028 _this.xhrOnLoad(_this.xhr);
28031 this.xhr.onerror = function()
28033 _this.xhrOnError(_this.xhr);
28036 var formData = new FormData();
28038 formData.append('returnHTML', 'NO');
28041 formData.append('crop', crop);
28044 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28045 formData.append(this.paramName, file, file.name);
28048 if(typeof(file.filename) != 'undefined'){
28049 formData.append('filename', file.filename);
28052 if(typeof(file.mimetype) != 'undefined'){
28053 formData.append('mimetype', file.mimetype);
28056 if(this.fireEvent('arrange', this, formData) != false){
28057 this.xhr.send(formData);
28061 xhrOnLoad : function(xhr)
28064 this.maskEl.unmask();
28067 if (xhr.readyState !== 4) {
28068 this.fireEvent('exception', this, xhr);
28072 var response = Roo.decode(xhr.responseText);
28074 if(!response.success){
28075 this.fireEvent('exception', this, xhr);
28079 var response = Roo.decode(xhr.responseText);
28081 this.fireEvent('upload', this, response);
28085 xhrOnError : function()
28088 this.maskEl.unmask();
28091 Roo.log('xhr on error');
28093 var response = Roo.decode(xhr.responseText);
28099 prepare : function(file)
28102 this.maskEl.mask(this.loadingText);
28108 if(typeof(file) === 'string'){
28109 this.loadCanvas(file);
28113 if(!file || !this.urlAPI){
28118 this.cropType = file.type;
28122 if(this.fireEvent('prepare', this, this.file) != false){
28124 var reader = new FileReader();
28126 reader.onload = function (e) {
28127 if (e.target.error) {
28128 Roo.log(e.target.error);
28132 var buffer = e.target.result,
28133 dataView = new DataView(buffer),
28135 maxOffset = dataView.byteLength - 4,
28139 if (dataView.getUint16(0) === 0xffd8) {
28140 while (offset < maxOffset) {
28141 markerBytes = dataView.getUint16(offset);
28143 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28144 markerLength = dataView.getUint16(offset + 2) + 2;
28145 if (offset + markerLength > dataView.byteLength) {
28146 Roo.log('Invalid meta data: Invalid segment size.');
28150 if(markerBytes == 0xffe1){
28151 _this.parseExifData(
28158 offset += markerLength;
28168 var url = _this.urlAPI.createObjectURL(_this.file);
28170 _this.loadCanvas(url);
28175 reader.readAsArrayBuffer(this.file);
28181 parseExifData : function(dataView, offset, length)
28183 var tiffOffset = offset + 10,
28187 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28188 // No Exif data, might be XMP data instead
28192 // Check for the ASCII code for "Exif" (0x45786966):
28193 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28194 // No Exif data, might be XMP data instead
28197 if (tiffOffset + 8 > dataView.byteLength) {
28198 Roo.log('Invalid Exif data: Invalid segment size.');
28201 // Check for the two null bytes:
28202 if (dataView.getUint16(offset + 8) !== 0x0000) {
28203 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28206 // Check the byte alignment:
28207 switch (dataView.getUint16(tiffOffset)) {
28209 littleEndian = true;
28212 littleEndian = false;
28215 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28218 // Check for the TIFF tag marker (0x002A):
28219 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28220 Roo.log('Invalid Exif data: Missing TIFF marker.');
28223 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28224 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28226 this.parseExifTags(
28229 tiffOffset + dirOffset,
28234 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28239 if (dirOffset + 6 > dataView.byteLength) {
28240 Roo.log('Invalid Exif data: Invalid directory offset.');
28243 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28244 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28245 if (dirEndOffset + 4 > dataView.byteLength) {
28246 Roo.log('Invalid Exif data: Invalid directory size.');
28249 for (i = 0; i < tagsNumber; i += 1) {
28253 dirOffset + 2 + 12 * i, // tag offset
28257 // Return the offset to the next directory:
28258 return dataView.getUint32(dirEndOffset, littleEndian);
28261 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28263 var tag = dataView.getUint16(offset, littleEndian);
28265 this.exif[tag] = this.getExifValue(
28269 dataView.getUint16(offset + 2, littleEndian), // tag type
28270 dataView.getUint32(offset + 4, littleEndian), // tag length
28275 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28277 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28286 Roo.log('Invalid Exif data: Invalid tag type.');
28290 tagSize = tagType.size * length;
28291 // Determine if the value is contained in the dataOffset bytes,
28292 // or if the value at the dataOffset is a pointer to the actual data:
28293 dataOffset = tagSize > 4 ?
28294 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28295 if (dataOffset + tagSize > dataView.byteLength) {
28296 Roo.log('Invalid Exif data: Invalid data offset.');
28299 if (length === 1) {
28300 return tagType.getValue(dataView, dataOffset, littleEndian);
28303 for (i = 0; i < length; i += 1) {
28304 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28307 if (tagType.ascii) {
28309 // Concatenate the chars:
28310 for (i = 0; i < values.length; i += 1) {
28312 // Ignore the terminating NULL byte(s):
28313 if (c === '\u0000') {
28325 Roo.apply(Roo.bootstrap.UploadCropbox, {
28327 'Orientation': 0x0112
28331 1: 0, //'top-left',
28333 3: 180, //'bottom-right',
28334 // 4: 'bottom-left',
28336 6: 90, //'right-top',
28337 // 7: 'right-bottom',
28338 8: 270 //'left-bottom'
28342 // byte, 8-bit unsigned int:
28344 getValue: function (dataView, dataOffset) {
28345 return dataView.getUint8(dataOffset);
28349 // ascii, 8-bit byte:
28351 getValue: function (dataView, dataOffset) {
28352 return String.fromCharCode(dataView.getUint8(dataOffset));
28357 // short, 16 bit int:
28359 getValue: function (dataView, dataOffset, littleEndian) {
28360 return dataView.getUint16(dataOffset, littleEndian);
28364 // long, 32 bit int:
28366 getValue: function (dataView, dataOffset, littleEndian) {
28367 return dataView.getUint32(dataOffset, littleEndian);
28371 // rational = two long values, first is numerator, second is denominator:
28373 getValue: function (dataView, dataOffset, littleEndian) {
28374 return dataView.getUint32(dataOffset, littleEndian) /
28375 dataView.getUint32(dataOffset + 4, littleEndian);
28379 // slong, 32 bit signed int:
28381 getValue: function (dataView, dataOffset, littleEndian) {
28382 return dataView.getInt32(dataOffset, littleEndian);
28386 // srational, two slongs, first is numerator, second is denominator:
28388 getValue: function (dataView, dataOffset, littleEndian) {
28389 return dataView.getInt32(dataOffset, littleEndian) /
28390 dataView.getInt32(dataOffset + 4, littleEndian);
28400 cls : 'btn-group roo-upload-cropbox-rotate-left',
28401 action : 'rotate-left',
28405 cls : 'btn btn-default',
28406 html : '<i class="fa fa-undo"></i>'
28412 cls : 'btn-group roo-upload-cropbox-picture',
28413 action : 'picture',
28417 cls : 'btn btn-default',
28418 html : '<i class="fa fa-picture-o"></i>'
28424 cls : 'btn-group roo-upload-cropbox-rotate-right',
28425 action : 'rotate-right',
28429 cls : 'btn btn-default',
28430 html : '<i class="fa fa-repeat"></i>'
28438 cls : 'btn-group roo-upload-cropbox-rotate-left',
28439 action : 'rotate-left',
28443 cls : 'btn btn-default',
28444 html : '<i class="fa fa-undo"></i>'
28450 cls : 'btn-group roo-upload-cropbox-download',
28451 action : 'download',
28455 cls : 'btn btn-default',
28456 html : '<i class="fa fa-download"></i>'
28462 cls : 'btn-group roo-upload-cropbox-crop',
28467 cls : 'btn btn-default',
28468 html : '<i class="fa fa-crop"></i>'
28474 cls : 'btn-group roo-upload-cropbox-trash',
28479 cls : 'btn btn-default',
28480 html : '<i class="fa fa-trash"></i>'
28486 cls : 'btn-group roo-upload-cropbox-rotate-right',
28487 action : 'rotate-right',
28491 cls : 'btn btn-default',
28492 html : '<i class="fa fa-repeat"></i>'
28500 cls : 'btn-group roo-upload-cropbox-rotate-left',
28501 action : 'rotate-left',
28505 cls : 'btn btn-default',
28506 html : '<i class="fa fa-undo"></i>'
28512 cls : 'btn-group roo-upload-cropbox-rotate-right',
28513 action : 'rotate-right',
28517 cls : 'btn btn-default',
28518 html : '<i class="fa fa-repeat"></i>'
28531 * @class Roo.bootstrap.DocumentManager
28532 * @extends Roo.bootstrap.Component
28533 * Bootstrap DocumentManager class
28534 * @cfg {String} paramName default 'imageUpload'
28535 * @cfg {String} toolTipName default 'filename'
28536 * @cfg {String} method default POST
28537 * @cfg {String} url action url
28538 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28539 * @cfg {Boolean} multiple multiple upload default true
28540 * @cfg {Number} thumbSize default 300
28541 * @cfg {String} fieldLabel
28542 * @cfg {Number} labelWidth default 4
28543 * @cfg {String} labelAlign (left|top) default left
28544 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28545 * @cfg {Number} labellg set the width of label (1-12)
28546 * @cfg {Number} labelmd set the width of label (1-12)
28547 * @cfg {Number} labelsm set the width of label (1-12)
28548 * @cfg {Number} labelxs set the width of label (1-12)
28551 * Create a new DocumentManager
28552 * @param {Object} config The config object
28555 Roo.bootstrap.DocumentManager = function(config){
28556 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28559 this.delegates = [];
28564 * Fire when initial the DocumentManager
28565 * @param {Roo.bootstrap.DocumentManager} this
28570 * inspect selected file
28571 * @param {Roo.bootstrap.DocumentManager} this
28572 * @param {File} file
28577 * Fire when xhr load exception
28578 * @param {Roo.bootstrap.DocumentManager} this
28579 * @param {XMLHttpRequest} xhr
28581 "exception" : true,
28583 * @event afterupload
28584 * Fire when xhr load exception
28585 * @param {Roo.bootstrap.DocumentManager} this
28586 * @param {XMLHttpRequest} xhr
28588 "afterupload" : true,
28591 * prepare the form data
28592 * @param {Roo.bootstrap.DocumentManager} this
28593 * @param {Object} formData
28598 * Fire when remove the file
28599 * @param {Roo.bootstrap.DocumentManager} this
28600 * @param {Object} file
28605 * Fire after refresh the file
28606 * @param {Roo.bootstrap.DocumentManager} this
28611 * Fire after click the image
28612 * @param {Roo.bootstrap.DocumentManager} this
28613 * @param {Object} file
28618 * Fire when upload a image and editable set to true
28619 * @param {Roo.bootstrap.DocumentManager} this
28620 * @param {Object} file
28624 * @event beforeselectfile
28625 * Fire before select file
28626 * @param {Roo.bootstrap.DocumentManager} this
28628 "beforeselectfile" : true,
28631 * Fire before process file
28632 * @param {Roo.bootstrap.DocumentManager} this
28633 * @param {Object} file
28637 * @event previewrendered
28638 * Fire when preview rendered
28639 * @param {Roo.bootstrap.DocumentManager} this
28640 * @param {Object} file
28642 "previewrendered" : true
28647 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28656 paramName : 'imageUpload',
28657 toolTipName : 'filename',
28660 labelAlign : 'left',
28670 getAutoCreate : function()
28672 var managerWidget = {
28674 cls : 'roo-document-manager',
28678 cls : 'roo-document-manager-selector',
28683 cls : 'roo-document-manager-uploader',
28687 cls : 'roo-document-manager-upload-btn',
28688 html : '<i class="fa fa-plus"></i>'
28699 cls : 'column col-md-12',
28704 if(this.fieldLabel.length){
28709 cls : 'column col-md-12',
28710 html : this.fieldLabel
28714 cls : 'column col-md-12',
28719 if(this.labelAlign == 'left'){
28724 html : this.fieldLabel
28733 if(this.labelWidth > 12){
28734 content[0].style = "width: " + this.labelWidth + 'px';
28737 if(this.labelWidth < 13 && this.labelmd == 0){
28738 this.labelmd = this.labelWidth;
28741 if(this.labellg > 0){
28742 content[0].cls += ' col-lg-' + this.labellg;
28743 content[1].cls += ' col-lg-' + (12 - this.labellg);
28746 if(this.labelmd > 0){
28747 content[0].cls += ' col-md-' + this.labelmd;
28748 content[1].cls += ' col-md-' + (12 - this.labelmd);
28751 if(this.labelsm > 0){
28752 content[0].cls += ' col-sm-' + this.labelsm;
28753 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28756 if(this.labelxs > 0){
28757 content[0].cls += ' col-xs-' + this.labelxs;
28758 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28766 cls : 'row clearfix',
28774 initEvents : function()
28776 this.managerEl = this.el.select('.roo-document-manager', true).first();
28777 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28779 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28780 this.selectorEl.hide();
28783 this.selectorEl.attr('multiple', 'multiple');
28786 this.selectorEl.on('change', this.onFileSelected, this);
28788 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28789 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28791 this.uploader.on('click', this.onUploaderClick, this);
28793 this.renderProgressDialog();
28797 window.addEventListener("resize", function() { _this.refresh(); } );
28799 this.fireEvent('initial', this);
28802 renderProgressDialog : function()
28806 this.progressDialog = new Roo.bootstrap.Modal({
28807 cls : 'roo-document-manager-progress-dialog',
28808 allow_close : false,
28818 btnclick : function() {
28819 _this.uploadCancel();
28825 this.progressDialog.render(Roo.get(document.body));
28827 this.progress = new Roo.bootstrap.Progress({
28828 cls : 'roo-document-manager-progress',
28833 this.progress.render(this.progressDialog.getChildContainer());
28835 this.progressBar = new Roo.bootstrap.ProgressBar({
28836 cls : 'roo-document-manager-progress-bar',
28839 aria_valuemax : 12,
28843 this.progressBar.render(this.progress.getChildContainer());
28846 onUploaderClick : function(e)
28848 e.preventDefault();
28850 if(this.fireEvent('beforeselectfile', this) != false){
28851 this.selectorEl.dom.click();
28856 onFileSelected : function(e)
28858 e.preventDefault();
28860 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28864 Roo.each(this.selectorEl.dom.files, function(file){
28865 if(this.fireEvent('inspect', this, file) != false){
28866 this.files.push(file);
28876 this.selectorEl.dom.value = '';
28878 if(!this.files || !this.files.length){
28882 if(this.boxes > 0 && this.files.length > this.boxes){
28883 this.files = this.files.slice(0, this.boxes);
28886 this.uploader.show();
28888 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28889 this.uploader.hide();
28898 Roo.each(this.files, function(file){
28900 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28901 var f = this.renderPreview(file);
28906 if(file.type.indexOf('image') != -1){
28907 this.delegates.push(
28909 _this.process(file);
28910 }).createDelegate(this)
28918 _this.process(file);
28919 }).createDelegate(this)
28924 this.files = files;
28926 this.delegates = this.delegates.concat(docs);
28928 if(!this.delegates.length){
28933 this.progressBar.aria_valuemax = this.delegates.length;
28940 arrange : function()
28942 if(!this.delegates.length){
28943 this.progressDialog.hide();
28948 var delegate = this.delegates.shift();
28950 this.progressDialog.show();
28952 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28954 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28959 refresh : function()
28961 this.uploader.show();
28963 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28964 this.uploader.hide();
28967 Roo.isTouch ? this.closable(false) : this.closable(true);
28969 this.fireEvent('refresh', this);
28972 onRemove : function(e, el, o)
28974 e.preventDefault();
28976 this.fireEvent('remove', this, o);
28980 remove : function(o)
28984 Roo.each(this.files, function(file){
28985 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
28994 this.files = files;
29001 Roo.each(this.files, function(file){
29006 file.target.remove();
29015 onClick : function(e, el, o)
29017 e.preventDefault();
29019 this.fireEvent('click', this, o);
29023 closable : function(closable)
29025 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29027 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29039 xhrOnLoad : function(xhr)
29041 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29045 if (xhr.readyState !== 4) {
29047 this.fireEvent('exception', this, xhr);
29051 var response = Roo.decode(xhr.responseText);
29053 if(!response.success){
29055 this.fireEvent('exception', this, xhr);
29059 var file = this.renderPreview(response.data);
29061 this.files.push(file);
29065 this.fireEvent('afterupload', this, xhr);
29069 xhrOnError : function(xhr)
29071 Roo.log('xhr on error');
29073 var response = Roo.decode(xhr.responseText);
29080 process : function(file)
29082 if(this.fireEvent('process', this, file) !== false){
29083 if(this.editable && file.type.indexOf('image') != -1){
29084 this.fireEvent('edit', this, file);
29088 this.uploadStart(file, false);
29095 uploadStart : function(file, crop)
29097 this.xhr = new XMLHttpRequest();
29099 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29104 file.xhr = this.xhr;
29106 this.managerEl.createChild({
29108 cls : 'roo-document-manager-loading',
29112 tooltip : file.name,
29113 cls : 'roo-document-manager-thumb',
29114 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29120 this.xhr.open(this.method, this.url, true);
29123 "Accept": "application/json",
29124 "Cache-Control": "no-cache",
29125 "X-Requested-With": "XMLHttpRequest"
29128 for (var headerName in headers) {
29129 var headerValue = headers[headerName];
29131 this.xhr.setRequestHeader(headerName, headerValue);
29137 this.xhr.onload = function()
29139 _this.xhrOnLoad(_this.xhr);
29142 this.xhr.onerror = function()
29144 _this.xhrOnError(_this.xhr);
29147 var formData = new FormData();
29149 formData.append('returnHTML', 'NO');
29152 formData.append('crop', crop);
29155 formData.append(this.paramName, file, file.name);
29162 if(this.fireEvent('prepare', this, formData, options) != false){
29164 if(options.manually){
29168 this.xhr.send(formData);
29172 this.uploadCancel();
29175 uploadCancel : function()
29181 this.delegates = [];
29183 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29190 renderPreview : function(file)
29192 if(typeof(file.target) != 'undefined' && file.target){
29196 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29198 var previewEl = this.managerEl.createChild({
29200 cls : 'roo-document-manager-preview',
29204 tooltip : file[this.toolTipName],
29205 cls : 'roo-document-manager-thumb',
29206 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29211 html : '<i class="fa fa-times-circle"></i>'
29216 var close = previewEl.select('button.close', true).first();
29218 close.on('click', this.onRemove, this, file);
29220 file.target = previewEl;
29222 var image = previewEl.select('img', true).first();
29226 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29228 image.on('click', this.onClick, this, file);
29230 this.fireEvent('previewrendered', this, file);
29236 onPreviewLoad : function(file, image)
29238 if(typeof(file.target) == 'undefined' || !file.target){
29242 var width = image.dom.naturalWidth || image.dom.width;
29243 var height = image.dom.naturalHeight || image.dom.height;
29245 if(width > height){
29246 file.target.addClass('wide');
29250 file.target.addClass('tall');
29255 uploadFromSource : function(file, crop)
29257 this.xhr = new XMLHttpRequest();
29259 this.managerEl.createChild({
29261 cls : 'roo-document-manager-loading',
29265 tooltip : file.name,
29266 cls : 'roo-document-manager-thumb',
29267 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29273 this.xhr.open(this.method, this.url, true);
29276 "Accept": "application/json",
29277 "Cache-Control": "no-cache",
29278 "X-Requested-With": "XMLHttpRequest"
29281 for (var headerName in headers) {
29282 var headerValue = headers[headerName];
29284 this.xhr.setRequestHeader(headerName, headerValue);
29290 this.xhr.onload = function()
29292 _this.xhrOnLoad(_this.xhr);
29295 this.xhr.onerror = function()
29297 _this.xhrOnError(_this.xhr);
29300 var formData = new FormData();
29302 formData.append('returnHTML', 'NO');
29304 formData.append('crop', crop);
29306 if(typeof(file.filename) != 'undefined'){
29307 formData.append('filename', file.filename);
29310 if(typeof(file.mimetype) != 'undefined'){
29311 formData.append('mimetype', file.mimetype);
29316 if(this.fireEvent('prepare', this, formData) != false){
29317 this.xhr.send(formData);
29327 * @class Roo.bootstrap.DocumentViewer
29328 * @extends Roo.bootstrap.Component
29329 * Bootstrap DocumentViewer class
29330 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29331 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29334 * Create a new DocumentViewer
29335 * @param {Object} config The config object
29338 Roo.bootstrap.DocumentViewer = function(config){
29339 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29344 * Fire after initEvent
29345 * @param {Roo.bootstrap.DocumentViewer} this
29351 * @param {Roo.bootstrap.DocumentViewer} this
29356 * Fire after download button
29357 * @param {Roo.bootstrap.DocumentViewer} this
29362 * Fire after trash button
29363 * @param {Roo.bootstrap.DocumentViewer} this
29370 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29372 showDownload : true,
29376 getAutoCreate : function()
29380 cls : 'roo-document-viewer',
29384 cls : 'roo-document-viewer-body',
29388 cls : 'roo-document-viewer-thumb',
29392 cls : 'roo-document-viewer-image'
29400 cls : 'roo-document-viewer-footer',
29403 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29407 cls : 'btn-group roo-document-viewer-download',
29411 cls : 'btn btn-default',
29412 html : '<i class="fa fa-download"></i>'
29418 cls : 'btn-group roo-document-viewer-trash',
29422 cls : 'btn btn-default',
29423 html : '<i class="fa fa-trash"></i>'
29436 initEvents : function()
29438 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29439 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29441 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29442 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29444 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29445 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29447 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29448 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29450 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29451 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29453 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29454 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29456 this.bodyEl.on('click', this.onClick, this);
29457 this.downloadBtn.on('click', this.onDownload, this);
29458 this.trashBtn.on('click', this.onTrash, this);
29460 this.downloadBtn.hide();
29461 this.trashBtn.hide();
29463 if(this.showDownload){
29464 this.downloadBtn.show();
29467 if(this.showTrash){
29468 this.trashBtn.show();
29471 if(!this.showDownload && !this.showTrash) {
29472 this.footerEl.hide();
29477 initial : function()
29479 this.fireEvent('initial', this);
29483 onClick : function(e)
29485 e.preventDefault();
29487 this.fireEvent('click', this);
29490 onDownload : function(e)
29492 e.preventDefault();
29494 this.fireEvent('download', this);
29497 onTrash : function(e)
29499 e.preventDefault();
29501 this.fireEvent('trash', this);
29513 * @class Roo.bootstrap.NavProgressBar
29514 * @extends Roo.bootstrap.Component
29515 * Bootstrap NavProgressBar class
29518 * Create a new nav progress bar
29519 * @param {Object} config The config object
29522 Roo.bootstrap.NavProgressBar = function(config){
29523 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29525 this.bullets = this.bullets || [];
29527 // Roo.bootstrap.NavProgressBar.register(this);
29531 * Fires when the active item changes
29532 * @param {Roo.bootstrap.NavProgressBar} this
29533 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29534 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29541 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29546 getAutoCreate : function()
29548 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29552 cls : 'roo-navigation-bar-group',
29556 cls : 'roo-navigation-top-bar'
29560 cls : 'roo-navigation-bullets-bar',
29564 cls : 'roo-navigation-bar'
29571 cls : 'roo-navigation-bottom-bar'
29581 initEvents: function()
29586 onRender : function(ct, position)
29588 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29590 if(this.bullets.length){
29591 Roo.each(this.bullets, function(b){
29600 addItem : function(cfg)
29602 var item = new Roo.bootstrap.NavProgressItem(cfg);
29604 item.parentId = this.id;
29605 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29608 var top = new Roo.bootstrap.Element({
29610 cls : 'roo-navigation-bar-text'
29613 var bottom = new Roo.bootstrap.Element({
29615 cls : 'roo-navigation-bar-text'
29618 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29619 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29621 var topText = new Roo.bootstrap.Element({
29623 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29626 var bottomText = new Roo.bootstrap.Element({
29628 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29631 topText.onRender(top.el, null);
29632 bottomText.onRender(bottom.el, null);
29635 item.bottomEl = bottom;
29638 this.barItems.push(item);
29643 getActive : function()
29645 var active = false;
29647 Roo.each(this.barItems, function(v){
29649 if (!v.isActive()) {
29661 setActiveItem : function(item)
29665 Roo.each(this.barItems, function(v){
29666 if (v.rid == item.rid) {
29670 if (v.isActive()) {
29671 v.setActive(false);
29676 item.setActive(true);
29678 this.fireEvent('changed', this, item, prev);
29681 getBarItem: function(rid)
29685 Roo.each(this.barItems, function(e) {
29686 if (e.rid != rid) {
29697 indexOfItem : function(item)
29701 Roo.each(this.barItems, function(v, i){
29703 if (v.rid != item.rid) {
29714 setActiveNext : function()
29716 var i = this.indexOfItem(this.getActive());
29718 if (i > this.barItems.length) {
29722 this.setActiveItem(this.barItems[i+1]);
29725 setActivePrev : function()
29727 var i = this.indexOfItem(this.getActive());
29733 this.setActiveItem(this.barItems[i-1]);
29736 format : function()
29738 if(!this.barItems.length){
29742 var width = 100 / this.barItems.length;
29744 Roo.each(this.barItems, function(i){
29745 i.el.setStyle('width', width + '%');
29746 i.topEl.el.setStyle('width', width + '%');
29747 i.bottomEl.el.setStyle('width', width + '%');
29756 * Nav Progress Item
29761 * @class Roo.bootstrap.NavProgressItem
29762 * @extends Roo.bootstrap.Component
29763 * Bootstrap NavProgressItem class
29764 * @cfg {String} rid the reference id
29765 * @cfg {Boolean} active (true|false) Is item active default false
29766 * @cfg {Boolean} disabled (true|false) Is item active default false
29767 * @cfg {String} html
29768 * @cfg {String} position (top|bottom) text position default bottom
29769 * @cfg {String} icon show icon instead of number
29772 * Create a new NavProgressItem
29773 * @param {Object} config The config object
29775 Roo.bootstrap.NavProgressItem = function(config){
29776 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29781 * The raw click event for the entire grid.
29782 * @param {Roo.bootstrap.NavProgressItem} this
29783 * @param {Roo.EventObject} e
29790 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29796 position : 'bottom',
29799 getAutoCreate : function()
29801 var iconCls = 'roo-navigation-bar-item-icon';
29803 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29807 cls: 'roo-navigation-bar-item',
29817 cfg.cls += ' active';
29820 cfg.cls += ' disabled';
29826 disable : function()
29828 this.setDisabled(true);
29831 enable : function()
29833 this.setDisabled(false);
29836 initEvents: function()
29838 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29840 this.iconEl.on('click', this.onClick, this);
29843 onClick : function(e)
29845 e.preventDefault();
29851 if(this.fireEvent('click', this, e) === false){
29855 this.parent().setActiveItem(this);
29858 isActive: function ()
29860 return this.active;
29863 setActive : function(state)
29865 if(this.active == state){
29869 this.active = state;
29872 this.el.addClass('active');
29876 this.el.removeClass('active');
29881 setDisabled : function(state)
29883 if(this.disabled == state){
29887 this.disabled = state;
29890 this.el.addClass('disabled');
29894 this.el.removeClass('disabled');
29897 tooltipEl : function()
29899 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29912 * @class Roo.bootstrap.FieldLabel
29913 * @extends Roo.bootstrap.Component
29914 * Bootstrap FieldLabel class
29915 * @cfg {String} html contents of the element
29916 * @cfg {String} tag tag of the element default label
29917 * @cfg {String} cls class of the element
29918 * @cfg {String} target label target
29919 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29920 * @cfg {String} invalidClass default "text-warning"
29921 * @cfg {String} validClass default "text-success"
29922 * @cfg {String} iconTooltip default "This field is required"
29923 * @cfg {String} indicatorpos (left|right) default left
29926 * Create a new FieldLabel
29927 * @param {Object} config The config object
29930 Roo.bootstrap.FieldLabel = function(config){
29931 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29936 * Fires after the field has been marked as invalid.
29937 * @param {Roo.form.FieldLabel} this
29938 * @param {String} msg The validation message
29943 * Fires after the field has been validated with no errors.
29944 * @param {Roo.form.FieldLabel} this
29950 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29957 invalidClass : 'has-warning',
29958 validClass : 'has-success',
29959 iconTooltip : 'This field is required',
29960 indicatorpos : 'left',
29962 getAutoCreate : function(){
29966 cls : 'roo-bootstrap-field-label ' + this.cls,
29971 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29972 tooltip : this.iconTooltip
29981 if(this.indicatorpos == 'right'){
29984 cls : 'roo-bootstrap-field-label ' + this.cls,
29993 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
29994 tooltip : this.iconTooltip
30003 initEvents: function()
30005 Roo.bootstrap.Element.superclass.initEvents.call(this);
30007 this.indicator = this.indicatorEl();
30009 if(this.indicator){
30010 this.indicator.removeClass('visible');
30011 this.indicator.addClass('invisible');
30014 Roo.bootstrap.FieldLabel.register(this);
30017 indicatorEl : function()
30019 var indicator = this.el.select('i.roo-required-indicator',true).first();
30030 * Mark this field as valid
30032 markValid : function()
30034 if(this.indicator){
30035 this.indicator.removeClass('visible');
30036 this.indicator.addClass('invisible');
30039 this.el.removeClass(this.invalidClass);
30041 this.el.addClass(this.validClass);
30043 this.fireEvent('valid', this);
30047 * Mark this field as invalid
30048 * @param {String} msg The validation message
30050 markInvalid : function(msg)
30052 if(this.indicator){
30053 this.indicator.removeClass('invisible');
30054 this.indicator.addClass('visible');
30057 this.el.removeClass(this.validClass);
30059 this.el.addClass(this.invalidClass);
30061 this.fireEvent('invalid', this, msg);
30067 Roo.apply(Roo.bootstrap.FieldLabel, {
30072 * register a FieldLabel Group
30073 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30075 register : function(label)
30077 if(this.groups.hasOwnProperty(label.target)){
30081 this.groups[label.target] = label;
30085 * fetch a FieldLabel Group based on the target
30086 * @param {string} target
30087 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30089 get: function(target) {
30090 if (typeof(this.groups[target]) == 'undefined') {
30094 return this.groups[target] ;
30103 * page DateSplitField.
30109 * @class Roo.bootstrap.DateSplitField
30110 * @extends Roo.bootstrap.Component
30111 * Bootstrap DateSplitField class
30112 * @cfg {string} fieldLabel - the label associated
30113 * @cfg {Number} labelWidth set the width of label (0-12)
30114 * @cfg {String} labelAlign (top|left)
30115 * @cfg {Boolean} dayAllowBlank (true|false) default false
30116 * @cfg {Boolean} monthAllowBlank (true|false) default false
30117 * @cfg {Boolean} yearAllowBlank (true|false) default false
30118 * @cfg {string} dayPlaceholder
30119 * @cfg {string} monthPlaceholder
30120 * @cfg {string} yearPlaceholder
30121 * @cfg {string} dayFormat default 'd'
30122 * @cfg {string} monthFormat default 'm'
30123 * @cfg {string} yearFormat default 'Y'
30124 * @cfg {Number} labellg set the width of label (1-12)
30125 * @cfg {Number} labelmd set the width of label (1-12)
30126 * @cfg {Number} labelsm set the width of label (1-12)
30127 * @cfg {Number} labelxs set the width of label (1-12)
30131 * Create a new DateSplitField
30132 * @param {Object} config The config object
30135 Roo.bootstrap.DateSplitField = function(config){
30136 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30142 * getting the data of years
30143 * @param {Roo.bootstrap.DateSplitField} this
30144 * @param {Object} years
30149 * getting the data of days
30150 * @param {Roo.bootstrap.DateSplitField} this
30151 * @param {Object} days
30156 * Fires after the field has been marked as invalid.
30157 * @param {Roo.form.Field} this
30158 * @param {String} msg The validation message
30163 * Fires after the field has been validated with no errors.
30164 * @param {Roo.form.Field} this
30170 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30173 labelAlign : 'top',
30175 dayAllowBlank : false,
30176 monthAllowBlank : false,
30177 yearAllowBlank : false,
30178 dayPlaceholder : '',
30179 monthPlaceholder : '',
30180 yearPlaceholder : '',
30184 isFormField : true,
30190 getAutoCreate : function()
30194 cls : 'row roo-date-split-field-group',
30199 cls : 'form-hidden-field roo-date-split-field-group-value',
30205 var labelCls = 'col-md-12';
30206 var contentCls = 'col-md-4';
30208 if(this.fieldLabel){
30212 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30216 html : this.fieldLabel
30221 if(this.labelAlign == 'left'){
30223 if(this.labelWidth > 12){
30224 label.style = "width: " + this.labelWidth + 'px';
30227 if(this.labelWidth < 13 && this.labelmd == 0){
30228 this.labelmd = this.labelWidth;
30231 if(this.labellg > 0){
30232 labelCls = ' col-lg-' + this.labellg;
30233 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30236 if(this.labelmd > 0){
30237 labelCls = ' col-md-' + this.labelmd;
30238 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30241 if(this.labelsm > 0){
30242 labelCls = ' col-sm-' + this.labelsm;
30243 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30246 if(this.labelxs > 0){
30247 labelCls = ' col-xs-' + this.labelxs;
30248 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30252 label.cls += ' ' + labelCls;
30254 cfg.cn.push(label);
30257 Roo.each(['day', 'month', 'year'], function(t){
30260 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30267 inputEl: function ()
30269 return this.el.select('.roo-date-split-field-group-value', true).first();
30272 onRender : function(ct, position)
30276 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30278 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30280 this.dayField = new Roo.bootstrap.ComboBox({
30281 allowBlank : this.dayAllowBlank,
30282 alwaysQuery : true,
30283 displayField : 'value',
30286 forceSelection : true,
30288 placeholder : this.dayPlaceholder,
30289 selectOnFocus : true,
30290 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30291 triggerAction : 'all',
30293 valueField : 'value',
30294 store : new Roo.data.SimpleStore({
30295 data : (function() {
30297 _this.fireEvent('days', _this, days);
30300 fields : [ 'value' ]
30303 select : function (_self, record, index)
30305 _this.setValue(_this.getValue());
30310 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30312 this.monthField = new Roo.bootstrap.MonthField({
30313 after : '<i class=\"fa fa-calendar\"></i>',
30314 allowBlank : this.monthAllowBlank,
30315 placeholder : this.monthPlaceholder,
30318 render : function (_self)
30320 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30321 e.preventDefault();
30325 select : function (_self, oldvalue, newvalue)
30327 _this.setValue(_this.getValue());
30332 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30334 this.yearField = new Roo.bootstrap.ComboBox({
30335 allowBlank : this.yearAllowBlank,
30336 alwaysQuery : true,
30337 displayField : 'value',
30340 forceSelection : true,
30342 placeholder : this.yearPlaceholder,
30343 selectOnFocus : true,
30344 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30345 triggerAction : 'all',
30347 valueField : 'value',
30348 store : new Roo.data.SimpleStore({
30349 data : (function() {
30351 _this.fireEvent('years', _this, years);
30354 fields : [ 'value' ]
30357 select : function (_self, record, index)
30359 _this.setValue(_this.getValue());
30364 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30367 setValue : function(v, format)
30369 this.inputEl.dom.value = v;
30371 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30373 var d = Date.parseDate(v, f);
30380 this.setDay(d.format(this.dayFormat));
30381 this.setMonth(d.format(this.monthFormat));
30382 this.setYear(d.format(this.yearFormat));
30389 setDay : function(v)
30391 this.dayField.setValue(v);
30392 this.inputEl.dom.value = this.getValue();
30397 setMonth : function(v)
30399 this.monthField.setValue(v, true);
30400 this.inputEl.dom.value = this.getValue();
30405 setYear : function(v)
30407 this.yearField.setValue(v);
30408 this.inputEl.dom.value = this.getValue();
30413 getDay : function()
30415 return this.dayField.getValue();
30418 getMonth : function()
30420 return this.monthField.getValue();
30423 getYear : function()
30425 return this.yearField.getValue();
30428 getValue : function()
30430 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30432 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30442 this.inputEl.dom.value = '';
30447 validate : function()
30449 var d = this.dayField.validate();
30450 var m = this.monthField.validate();
30451 var y = this.yearField.validate();
30456 (!this.dayAllowBlank && !d) ||
30457 (!this.monthAllowBlank && !m) ||
30458 (!this.yearAllowBlank && !y)
30463 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30472 this.markInvalid();
30477 markValid : function()
30480 var label = this.el.select('label', true).first();
30481 var icon = this.el.select('i.fa-star', true).first();
30487 this.fireEvent('valid', this);
30491 * Mark this field as invalid
30492 * @param {String} msg The validation message
30494 markInvalid : function(msg)
30497 var label = this.el.select('label', true).first();
30498 var icon = this.el.select('i.fa-star', true).first();
30500 if(label && !icon){
30501 this.el.select('.roo-date-split-field-label', true).createChild({
30503 cls : 'text-danger fa fa-lg fa-star',
30504 tooltip : 'This field is required',
30505 style : 'margin-right:5px;'
30509 this.fireEvent('invalid', this, msg);
30512 clearInvalid : function()
30514 var label = this.el.select('label', true).first();
30515 var icon = this.el.select('i.fa-star', true).first();
30521 this.fireEvent('valid', this);
30524 getName: function()
30534 * http://masonry.desandro.com
30536 * The idea is to render all the bricks based on vertical width...
30538 * The original code extends 'outlayer' - we might need to use that....
30544 * @class Roo.bootstrap.LayoutMasonry
30545 * @extends Roo.bootstrap.Component
30546 * Bootstrap Layout Masonry class
30549 * Create a new Element
30550 * @param {Object} config The config object
30553 Roo.bootstrap.LayoutMasonry = function(config){
30555 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30559 Roo.bootstrap.LayoutMasonry.register(this);
30565 * Fire after layout the items
30566 * @param {Roo.bootstrap.LayoutMasonry} this
30567 * @param {Roo.EventObject} e
30574 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30577 * @cfg {Boolean} isLayoutInstant = no animation?
30579 isLayoutInstant : false, // needed?
30582 * @cfg {Number} boxWidth width of the columns
30587 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30592 * @cfg {Number} padWidth padding below box..
30597 * @cfg {Number} gutter gutter width..
30602 * @cfg {Number} maxCols maximum number of columns
30608 * @cfg {Boolean} isAutoInitial defalut true
30610 isAutoInitial : true,
30615 * @cfg {Boolean} isHorizontal defalut false
30617 isHorizontal : false,
30619 currentSize : null,
30625 bricks: null, //CompositeElement
30629 _isLayoutInited : false,
30631 // isAlternative : false, // only use for vertical layout...
30634 * @cfg {Number} alternativePadWidth padding below box..
30636 alternativePadWidth : 50,
30638 selectedBrick : [],
30640 getAutoCreate : function(){
30642 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30646 cls: 'blog-masonary-wrapper ' + this.cls,
30648 cls : 'mas-boxes masonary'
30655 getChildContainer: function( )
30657 if (this.boxesEl) {
30658 return this.boxesEl;
30661 this.boxesEl = this.el.select('.mas-boxes').first();
30663 return this.boxesEl;
30667 initEvents : function()
30671 if(this.isAutoInitial){
30672 Roo.log('hook children rendered');
30673 this.on('childrenrendered', function() {
30674 Roo.log('children rendered');
30680 initial : function()
30682 this.selectedBrick = [];
30684 this.currentSize = this.el.getBox(true);
30686 Roo.EventManager.onWindowResize(this.resize, this);
30688 if(!this.isAutoInitial){
30696 //this.layout.defer(500,this);
30700 resize : function()
30702 var cs = this.el.getBox(true);
30705 this.currentSize.width == cs.width &&
30706 this.currentSize.x == cs.x &&
30707 this.currentSize.height == cs.height &&
30708 this.currentSize.y == cs.y
30710 Roo.log("no change in with or X or Y");
30714 this.currentSize = cs;
30720 layout : function()
30722 this._resetLayout();
30724 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30726 this.layoutItems( isInstant );
30728 this._isLayoutInited = true;
30730 this.fireEvent('layout', this);
30734 _resetLayout : function()
30736 if(this.isHorizontal){
30737 this.horizontalMeasureColumns();
30741 this.verticalMeasureColumns();
30745 verticalMeasureColumns : function()
30747 this.getContainerWidth();
30749 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30750 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30754 var boxWidth = this.boxWidth + this.padWidth;
30756 if(this.containerWidth < this.boxWidth){
30757 boxWidth = this.containerWidth
30760 var containerWidth = this.containerWidth;
30762 var cols = Math.floor(containerWidth / boxWidth);
30764 this.cols = Math.max( cols, 1 );
30766 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30768 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30770 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30772 this.colWidth = boxWidth + avail - this.padWidth;
30774 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30775 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30778 horizontalMeasureColumns : function()
30780 this.getContainerWidth();
30782 var boxWidth = this.boxWidth;
30784 if(this.containerWidth < boxWidth){
30785 boxWidth = this.containerWidth;
30788 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30790 this.el.setHeight(boxWidth);
30794 getContainerWidth : function()
30796 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30799 layoutItems : function( isInstant )
30801 Roo.log(this.bricks);
30803 var items = Roo.apply([], this.bricks);
30805 if(this.isHorizontal){
30806 this._horizontalLayoutItems( items , isInstant );
30810 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30811 // this._verticalAlternativeLayoutItems( items , isInstant );
30815 this._verticalLayoutItems( items , isInstant );
30819 _verticalLayoutItems : function ( items , isInstant)
30821 if ( !items || !items.length ) {
30826 ['xs', 'xs', 'xs', 'tall'],
30827 ['xs', 'xs', 'tall'],
30828 ['xs', 'xs', 'sm'],
30829 ['xs', 'xs', 'xs'],
30835 ['sm', 'xs', 'xs'],
30839 ['tall', 'xs', 'xs', 'xs'],
30840 ['tall', 'xs', 'xs'],
30852 Roo.each(items, function(item, k){
30854 switch (item.size) {
30855 // these layouts take up a full box,
30866 boxes.push([item]);
30889 var filterPattern = function(box, length)
30897 var pattern = box.slice(0, length);
30901 Roo.each(pattern, function(i){
30902 format.push(i.size);
30905 Roo.each(standard, function(s){
30907 if(String(s) != String(format)){
30916 if(!match && length == 1){
30921 filterPattern(box, length - 1);
30925 queue.push(pattern);
30927 box = box.slice(length, box.length);
30929 filterPattern(box, 4);
30935 Roo.each(boxes, function(box, k){
30941 if(box.length == 1){
30946 filterPattern(box, 4);
30950 this._processVerticalLayoutQueue( queue, isInstant );
30954 // _verticalAlternativeLayoutItems : function( items , isInstant )
30956 // if ( !items || !items.length ) {
30960 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30964 _horizontalLayoutItems : function ( items , isInstant)
30966 if ( !items || !items.length || items.length < 3) {
30972 var eItems = items.slice(0, 3);
30974 items = items.slice(3, items.length);
30977 ['xs', 'xs', 'xs', 'wide'],
30978 ['xs', 'xs', 'wide'],
30979 ['xs', 'xs', 'sm'],
30980 ['xs', 'xs', 'xs'],
30986 ['sm', 'xs', 'xs'],
30990 ['wide', 'xs', 'xs', 'xs'],
30991 ['wide', 'xs', 'xs'],
31004 Roo.each(items, function(item, k){
31006 switch (item.size) {
31017 boxes.push([item]);
31041 var filterPattern = function(box, length)
31049 var pattern = box.slice(0, length);
31053 Roo.each(pattern, function(i){
31054 format.push(i.size);
31057 Roo.each(standard, function(s){
31059 if(String(s) != String(format)){
31068 if(!match && length == 1){
31073 filterPattern(box, length - 1);
31077 queue.push(pattern);
31079 box = box.slice(length, box.length);
31081 filterPattern(box, 4);
31087 Roo.each(boxes, function(box, k){
31093 if(box.length == 1){
31098 filterPattern(box, 4);
31105 var pos = this.el.getBox(true);
31109 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31111 var hit_end = false;
31113 Roo.each(queue, function(box){
31117 Roo.each(box, function(b){
31119 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31129 Roo.each(box, function(b){
31131 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31134 mx = Math.max(mx, b.x);
31138 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31142 Roo.each(box, function(b){
31144 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31158 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31161 /** Sets position of item in DOM
31162 * @param {Element} item
31163 * @param {Number} x - horizontal position
31164 * @param {Number} y - vertical position
31165 * @param {Boolean} isInstant - disables transitions
31167 _processVerticalLayoutQueue : function( queue, isInstant )
31169 var pos = this.el.getBox(true);
31174 for (var i = 0; i < this.cols; i++){
31178 Roo.each(queue, function(box, k){
31180 var col = k % this.cols;
31182 Roo.each(box, function(b,kk){
31184 b.el.position('absolute');
31186 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31187 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31189 if(b.size == 'md-left' || b.size == 'md-right'){
31190 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31191 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31194 b.el.setWidth(width);
31195 b.el.setHeight(height);
31197 b.el.select('iframe',true).setSize(width,height);
31201 for (var i = 0; i < this.cols; i++){
31203 if(maxY[i] < maxY[col]){
31208 col = Math.min(col, i);
31212 x = pos.x + col * (this.colWidth + this.padWidth);
31216 var positions = [];
31218 switch (box.length){
31220 positions = this.getVerticalOneBoxColPositions(x, y, box);
31223 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31226 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31229 positions = this.getVerticalFourBoxColPositions(x, y, box);
31235 Roo.each(box, function(b,kk){
31237 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31239 var sz = b.el.getSize();
31241 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31249 for (var i = 0; i < this.cols; i++){
31250 mY = Math.max(mY, maxY[i]);
31253 this.el.setHeight(mY - pos.y);
31257 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31259 // var pos = this.el.getBox(true);
31262 // var maxX = pos.right;
31264 // var maxHeight = 0;
31266 // Roo.each(items, function(item, k){
31270 // item.el.position('absolute');
31272 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31274 // item.el.setWidth(width);
31276 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31278 // item.el.setHeight(height);
31281 // item.el.setXY([x, y], isInstant ? false : true);
31283 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31286 // y = y + height + this.alternativePadWidth;
31288 // maxHeight = maxHeight + height + this.alternativePadWidth;
31292 // this.el.setHeight(maxHeight);
31296 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31298 var pos = this.el.getBox(true);
31303 var maxX = pos.right;
31305 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31307 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31309 Roo.each(queue, function(box, k){
31311 Roo.each(box, function(b, kk){
31313 b.el.position('absolute');
31315 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31316 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31318 if(b.size == 'md-left' || b.size == 'md-right'){
31319 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31320 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31323 b.el.setWidth(width);
31324 b.el.setHeight(height);
31332 var positions = [];
31334 switch (box.length){
31336 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31339 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31342 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31345 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31351 Roo.each(box, function(b,kk){
31353 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31355 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31363 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31365 Roo.each(eItems, function(b,k){
31367 b.size = (k == 0) ? 'sm' : 'xs';
31368 b.x = (k == 0) ? 2 : 1;
31369 b.y = (k == 0) ? 2 : 1;
31371 b.el.position('absolute');
31373 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31375 b.el.setWidth(width);
31377 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31379 b.el.setHeight(height);
31383 var positions = [];
31386 x : maxX - this.unitWidth * 2 - this.gutter,
31391 x : maxX - this.unitWidth,
31392 y : minY + (this.unitWidth + this.gutter) * 2
31396 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31400 Roo.each(eItems, function(b,k){
31402 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31408 getVerticalOneBoxColPositions : function(x, y, box)
31412 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31414 if(box[0].size == 'md-left'){
31418 if(box[0].size == 'md-right'){
31423 x : x + (this.unitWidth + this.gutter) * rand,
31430 getVerticalTwoBoxColPositions : function(x, y, box)
31434 if(box[0].size == 'xs'){
31438 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31442 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31456 x : x + (this.unitWidth + this.gutter) * 2,
31457 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31464 getVerticalThreeBoxColPositions : function(x, y, box)
31468 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31476 x : x + (this.unitWidth + this.gutter) * 1,
31481 x : x + (this.unitWidth + this.gutter) * 2,
31489 if(box[0].size == 'xs' && box[1].size == 'xs'){
31498 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31502 x : x + (this.unitWidth + this.gutter) * 1,
31516 x : x + (this.unitWidth + this.gutter) * 2,
31521 x : x + (this.unitWidth + this.gutter) * 2,
31522 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31529 getVerticalFourBoxColPositions : function(x, y, box)
31533 if(box[0].size == 'xs'){
31542 y : y + (this.unitHeight + this.gutter) * 1
31547 y : y + (this.unitHeight + this.gutter) * 2
31551 x : x + (this.unitWidth + this.gutter) * 1,
31565 x : x + (this.unitWidth + this.gutter) * 2,
31570 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31571 y : y + (this.unitHeight + this.gutter) * 1
31575 x : x + (this.unitWidth + this.gutter) * 2,
31576 y : y + (this.unitWidth + this.gutter) * 2
31583 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31587 if(box[0].size == 'md-left'){
31589 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31596 if(box[0].size == 'md-right'){
31598 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31599 y : minY + (this.unitWidth + this.gutter) * 1
31605 var rand = Math.floor(Math.random() * (4 - box[0].y));
31608 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31609 y : minY + (this.unitWidth + this.gutter) * rand
31616 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31620 if(box[0].size == 'xs'){
31623 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31628 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31629 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31637 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31642 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31643 y : minY + (this.unitWidth + this.gutter) * 2
31650 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31654 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31657 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31662 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31663 y : minY + (this.unitWidth + this.gutter) * 1
31667 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31668 y : minY + (this.unitWidth + this.gutter) * 2
31675 if(box[0].size == 'xs' && box[1].size == 'xs'){
31678 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31683 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31688 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31689 y : minY + (this.unitWidth + this.gutter) * 1
31697 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31702 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31703 y : minY + (this.unitWidth + this.gutter) * 2
31707 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31708 y : minY + (this.unitWidth + this.gutter) * 2
31715 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31719 if(box[0].size == 'xs'){
31722 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31727 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31732 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31737 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31738 y : minY + (this.unitWidth + this.gutter) * 1
31746 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31751 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31752 y : minY + (this.unitWidth + this.gutter) * 2
31756 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31757 y : minY + (this.unitWidth + this.gutter) * 2
31761 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31762 y : minY + (this.unitWidth + this.gutter) * 2
31770 * remove a Masonry Brick
31771 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31773 removeBrick : function(brick_id)
31779 for (var i = 0; i<this.bricks.length; i++) {
31780 if (this.bricks[i].id == brick_id) {
31781 this.bricks.splice(i,1);
31782 this.el.dom.removeChild(Roo.get(brick_id).dom);
31789 * adds a Masonry Brick
31790 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31792 addBrick : function(cfg)
31794 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31795 //this.register(cn);
31796 cn.parentId = this.id;
31797 cn.onRender(this.el, null);
31802 * register a Masonry Brick
31803 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31806 register : function(brick)
31808 this.bricks.push(brick);
31809 brick.masonryId = this.id;
31813 * clear all the Masonry Brick
31815 clearAll : function()
31818 //this.getChildContainer().dom.innerHTML = "";
31819 this.el.dom.innerHTML = '';
31822 getSelected : function()
31824 if (!this.selectedBrick) {
31828 return this.selectedBrick;
31832 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31836 * register a Masonry Layout
31837 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31840 register : function(layout)
31842 this.groups[layout.id] = layout;
31845 * fetch a Masonry Layout based on the masonry layout ID
31846 * @param {string} the masonry layout to add
31847 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31850 get: function(layout_id) {
31851 if (typeof(this.groups[layout_id]) == 'undefined') {
31854 return this.groups[layout_id] ;
31866 * http://masonry.desandro.com
31868 * The idea is to render all the bricks based on vertical width...
31870 * The original code extends 'outlayer' - we might need to use that....
31876 * @class Roo.bootstrap.LayoutMasonryAuto
31877 * @extends Roo.bootstrap.Component
31878 * Bootstrap Layout Masonry class
31881 * Create a new Element
31882 * @param {Object} config The config object
31885 Roo.bootstrap.LayoutMasonryAuto = function(config){
31886 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31889 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31892 * @cfg {Boolean} isFitWidth - resize the width..
31894 isFitWidth : false, // options..
31896 * @cfg {Boolean} isOriginLeft = left align?
31898 isOriginLeft : true,
31900 * @cfg {Boolean} isOriginTop = top align?
31902 isOriginTop : false,
31904 * @cfg {Boolean} isLayoutInstant = no animation?
31906 isLayoutInstant : false, // needed?
31908 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31910 isResizingContainer : true,
31912 * @cfg {Number} columnWidth width of the columns
31918 * @cfg {Number} maxCols maximum number of columns
31923 * @cfg {Number} padHeight padding below box..
31929 * @cfg {Boolean} isAutoInitial defalut true
31932 isAutoInitial : true,
31938 initialColumnWidth : 0,
31939 currentSize : null,
31941 colYs : null, // array.
31948 bricks: null, //CompositeElement
31949 cols : 0, // array?
31950 // element : null, // wrapped now this.el
31951 _isLayoutInited : null,
31954 getAutoCreate : function(){
31958 cls: 'blog-masonary-wrapper ' + this.cls,
31960 cls : 'mas-boxes masonary'
31967 getChildContainer: function( )
31969 if (this.boxesEl) {
31970 return this.boxesEl;
31973 this.boxesEl = this.el.select('.mas-boxes').first();
31975 return this.boxesEl;
31979 initEvents : function()
31983 if(this.isAutoInitial){
31984 Roo.log('hook children rendered');
31985 this.on('childrenrendered', function() {
31986 Roo.log('children rendered');
31993 initial : function()
31995 this.reloadItems();
31997 this.currentSize = this.el.getBox(true);
31999 /// was window resize... - let's see if this works..
32000 Roo.EventManager.onWindowResize(this.resize, this);
32002 if(!this.isAutoInitial){
32007 this.layout.defer(500,this);
32010 reloadItems: function()
32012 this.bricks = this.el.select('.masonry-brick', true);
32014 this.bricks.each(function(b) {
32015 //Roo.log(b.getSize());
32016 if (!b.attr('originalwidth')) {
32017 b.attr('originalwidth', b.getSize().width);
32022 Roo.log(this.bricks.elements.length);
32025 resize : function()
32028 var cs = this.el.getBox(true);
32030 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32031 Roo.log("no change in with or X");
32034 this.currentSize = cs;
32038 layout : function()
32041 this._resetLayout();
32042 //this._manageStamps();
32044 // don't animate first layout
32045 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32046 this.layoutItems( isInstant );
32048 // flag for initalized
32049 this._isLayoutInited = true;
32052 layoutItems : function( isInstant )
32054 //var items = this._getItemsForLayout( this.items );
32055 // original code supports filtering layout items.. we just ignore it..
32057 this._layoutItems( this.bricks , isInstant );
32059 this._postLayout();
32061 _layoutItems : function ( items , isInstant)
32063 //this.fireEvent( 'layout', this, items );
32066 if ( !items || !items.elements.length ) {
32067 // no items, emit event with empty array
32072 items.each(function(item) {
32073 Roo.log("layout item");
32075 // get x/y object from method
32076 var position = this._getItemLayoutPosition( item );
32078 position.item = item;
32079 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32080 queue.push( position );
32083 this._processLayoutQueue( queue );
32085 /** Sets position of item in DOM
32086 * @param {Element} item
32087 * @param {Number} x - horizontal position
32088 * @param {Number} y - vertical position
32089 * @param {Boolean} isInstant - disables transitions
32091 _processLayoutQueue : function( queue )
32093 for ( var i=0, len = queue.length; i < len; i++ ) {
32094 var obj = queue[i];
32095 obj.item.position('absolute');
32096 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32102 * Any logic you want to do after each layout,
32103 * i.e. size the container
32105 _postLayout : function()
32107 this.resizeContainer();
32110 resizeContainer : function()
32112 if ( !this.isResizingContainer ) {
32115 var size = this._getContainerSize();
32117 this.el.setSize(size.width,size.height);
32118 this.boxesEl.setSize(size.width,size.height);
32124 _resetLayout : function()
32126 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32127 this.colWidth = this.el.getWidth();
32128 //this.gutter = this.el.getWidth();
32130 this.measureColumns();
32136 this.colYs.push( 0 );
32142 measureColumns : function()
32144 this.getContainerWidth();
32145 // if columnWidth is 0, default to outerWidth of first item
32146 if ( !this.columnWidth ) {
32147 var firstItem = this.bricks.first();
32148 Roo.log(firstItem);
32149 this.columnWidth = this.containerWidth;
32150 if (firstItem && firstItem.attr('originalwidth') ) {
32151 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32153 // columnWidth fall back to item of first element
32154 Roo.log("set column width?");
32155 this.initialColumnWidth = this.columnWidth ;
32157 // if first elem has no width, default to size of container
32162 if (this.initialColumnWidth) {
32163 this.columnWidth = this.initialColumnWidth;
32168 // column width is fixed at the top - however if container width get's smaller we should
32171 // this bit calcs how man columns..
32173 var columnWidth = this.columnWidth += this.gutter;
32175 // calculate columns
32176 var containerWidth = this.containerWidth + this.gutter;
32178 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32179 // fix rounding errors, typically with gutters
32180 var excess = columnWidth - containerWidth % columnWidth;
32183 // if overshoot is less than a pixel, round up, otherwise floor it
32184 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32185 cols = Math[ mathMethod ]( cols );
32186 this.cols = Math.max( cols, 1 );
32187 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32189 // padding positioning..
32190 var totalColWidth = this.cols * this.columnWidth;
32191 var padavail = this.containerWidth - totalColWidth;
32192 // so for 2 columns - we need 3 'pads'
32194 var padNeeded = (1+this.cols) * this.padWidth;
32196 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32198 this.columnWidth += padExtra
32199 //this.padWidth = Math.floor(padavail / ( this.cols));
32201 // adjust colum width so that padding is fixed??
32203 // we have 3 columns ... total = width * 3
32204 // we have X left over... that should be used by
32206 //if (this.expandC) {
32214 getContainerWidth : function()
32216 /* // container is parent if fit width
32217 var container = this.isFitWidth ? this.element.parentNode : this.element;
32218 // check that this.size and size are there
32219 // IE8 triggers resize on body size change, so they might not be
32221 var size = getSize( container ); //FIXME
32222 this.containerWidth = size && size.innerWidth; //FIXME
32225 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32229 _getItemLayoutPosition : function( item ) // what is item?
32231 // we resize the item to our columnWidth..
32233 item.setWidth(this.columnWidth);
32234 item.autoBoxAdjust = false;
32236 var sz = item.getSize();
32238 // how many columns does this brick span
32239 var remainder = this.containerWidth % this.columnWidth;
32241 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32242 // round if off by 1 pixel, otherwise use ceil
32243 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32244 colSpan = Math.min( colSpan, this.cols );
32246 // normally this should be '1' as we dont' currently allow multi width columns..
32248 var colGroup = this._getColGroup( colSpan );
32249 // get the minimum Y value from the columns
32250 var minimumY = Math.min.apply( Math, colGroup );
32251 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32253 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32255 // position the brick
32257 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32258 y: this.currentSize.y + minimumY + this.padHeight
32262 // apply setHeight to necessary columns
32263 var setHeight = minimumY + sz.height + this.padHeight;
32264 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32266 var setSpan = this.cols + 1 - colGroup.length;
32267 for ( var i = 0; i < setSpan; i++ ) {
32268 this.colYs[ shortColIndex + i ] = setHeight ;
32275 * @param {Number} colSpan - number of columns the element spans
32276 * @returns {Array} colGroup
32278 _getColGroup : function( colSpan )
32280 if ( colSpan < 2 ) {
32281 // if brick spans only one column, use all the column Ys
32286 // how many different places could this brick fit horizontally
32287 var groupCount = this.cols + 1 - colSpan;
32288 // for each group potential horizontal position
32289 for ( var i = 0; i < groupCount; i++ ) {
32290 // make an array of colY values for that one group
32291 var groupColYs = this.colYs.slice( i, i + colSpan );
32292 // and get the max value of the array
32293 colGroup[i] = Math.max.apply( Math, groupColYs );
32298 _manageStamp : function( stamp )
32300 var stampSize = stamp.getSize();
32301 var offset = stamp.getBox();
32302 // get the columns that this stamp affects
32303 var firstX = this.isOriginLeft ? offset.x : offset.right;
32304 var lastX = firstX + stampSize.width;
32305 var firstCol = Math.floor( firstX / this.columnWidth );
32306 firstCol = Math.max( 0, firstCol );
32308 var lastCol = Math.floor( lastX / this.columnWidth );
32309 // lastCol should not go over if multiple of columnWidth #425
32310 lastCol -= lastX % this.columnWidth ? 0 : 1;
32311 lastCol = Math.min( this.cols - 1, lastCol );
32313 // set colYs to bottom of the stamp
32314 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32317 for ( var i = firstCol; i <= lastCol; i++ ) {
32318 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32323 _getContainerSize : function()
32325 this.maxY = Math.max.apply( Math, this.colYs );
32330 if ( this.isFitWidth ) {
32331 size.width = this._getContainerFitWidth();
32337 _getContainerFitWidth : function()
32339 var unusedCols = 0;
32340 // count unused columns
32343 if ( this.colYs[i] !== 0 ) {
32348 // fit container to columns that have been used
32349 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32352 needsResizeLayout : function()
32354 var previousWidth = this.containerWidth;
32355 this.getContainerWidth();
32356 return previousWidth !== this.containerWidth;
32371 * @class Roo.bootstrap.MasonryBrick
32372 * @extends Roo.bootstrap.Component
32373 * Bootstrap MasonryBrick class
32376 * Create a new MasonryBrick
32377 * @param {Object} config The config object
32380 Roo.bootstrap.MasonryBrick = function(config){
32382 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32384 Roo.bootstrap.MasonryBrick.register(this);
32390 * When a MasonryBrick is clcik
32391 * @param {Roo.bootstrap.MasonryBrick} this
32392 * @param {Roo.EventObject} e
32398 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32401 * @cfg {String} title
32405 * @cfg {String} html
32409 * @cfg {String} bgimage
32413 * @cfg {String} videourl
32417 * @cfg {String} cls
32421 * @cfg {String} href
32425 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32430 * @cfg {String} placetitle (center|bottom)
32435 * @cfg {Boolean} isFitContainer defalut true
32437 isFitContainer : true,
32440 * @cfg {Boolean} preventDefault defalut false
32442 preventDefault : false,
32445 * @cfg {Boolean} inverse defalut false
32447 maskInverse : false,
32449 getAutoCreate : function()
32451 if(!this.isFitContainer){
32452 return this.getSplitAutoCreate();
32455 var cls = 'masonry-brick masonry-brick-full';
32457 if(this.href.length){
32458 cls += ' masonry-brick-link';
32461 if(this.bgimage.length){
32462 cls += ' masonry-brick-image';
32465 if(this.maskInverse){
32466 cls += ' mask-inverse';
32469 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32470 cls += ' enable-mask';
32474 cls += ' masonry-' + this.size + '-brick';
32477 if(this.placetitle.length){
32479 switch (this.placetitle) {
32481 cls += ' masonry-center-title';
32484 cls += ' masonry-bottom-title';
32491 if(!this.html.length && !this.bgimage.length){
32492 cls += ' masonry-center-title';
32495 if(!this.html.length && this.bgimage.length){
32496 cls += ' masonry-bottom-title';
32501 cls += ' ' + this.cls;
32505 tag: (this.href.length) ? 'a' : 'div',
32510 cls: 'masonry-brick-mask'
32514 cls: 'masonry-brick-paragraph',
32520 if(this.href.length){
32521 cfg.href = this.href;
32524 var cn = cfg.cn[1].cn;
32526 if(this.title.length){
32529 cls: 'masonry-brick-title',
32534 if(this.html.length){
32537 cls: 'masonry-brick-text',
32542 if (!this.title.length && !this.html.length) {
32543 cfg.cn[1].cls += ' hide';
32546 if(this.bgimage.length){
32549 cls: 'masonry-brick-image-view',
32554 if(this.videourl.length){
32555 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32556 // youtube support only?
32559 cls: 'masonry-brick-image-view',
32562 allowfullscreen : true
32570 getSplitAutoCreate : function()
32572 var cls = 'masonry-brick masonry-brick-split';
32574 if(this.href.length){
32575 cls += ' masonry-brick-link';
32578 if(this.bgimage.length){
32579 cls += ' masonry-brick-image';
32583 cls += ' masonry-' + this.size + '-brick';
32586 switch (this.placetitle) {
32588 cls += ' masonry-center-title';
32591 cls += ' masonry-bottom-title';
32594 if(!this.bgimage.length){
32595 cls += ' masonry-center-title';
32598 if(this.bgimage.length){
32599 cls += ' masonry-bottom-title';
32605 cls += ' ' + this.cls;
32609 tag: (this.href.length) ? 'a' : 'div',
32614 cls: 'masonry-brick-split-head',
32618 cls: 'masonry-brick-paragraph',
32625 cls: 'masonry-brick-split-body',
32631 if(this.href.length){
32632 cfg.href = this.href;
32635 if(this.title.length){
32636 cfg.cn[0].cn[0].cn.push({
32638 cls: 'masonry-brick-title',
32643 if(this.html.length){
32644 cfg.cn[1].cn.push({
32646 cls: 'masonry-brick-text',
32651 if(this.bgimage.length){
32652 cfg.cn[0].cn.push({
32654 cls: 'masonry-brick-image-view',
32659 if(this.videourl.length){
32660 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32661 // youtube support only?
32662 cfg.cn[0].cn.cn.push({
32664 cls: 'masonry-brick-image-view',
32667 allowfullscreen : true
32674 initEvents: function()
32676 switch (this.size) {
32709 this.el.on('touchstart', this.onTouchStart, this);
32710 this.el.on('touchmove', this.onTouchMove, this);
32711 this.el.on('touchend', this.onTouchEnd, this);
32712 this.el.on('contextmenu', this.onContextMenu, this);
32714 this.el.on('mouseenter' ,this.enter, this);
32715 this.el.on('mouseleave', this.leave, this);
32716 this.el.on('click', this.onClick, this);
32719 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32720 this.parent().bricks.push(this);
32725 onClick: function(e, el)
32727 var time = this.endTimer - this.startTimer;
32728 // Roo.log(e.preventDefault());
32731 e.preventDefault();
32736 if(!this.preventDefault){
32740 e.preventDefault();
32742 if (this.activcClass != '') {
32743 this.selectBrick();
32746 this.fireEvent('click', this);
32749 enter: function(e, el)
32751 e.preventDefault();
32753 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32757 if(this.bgimage.length && this.html.length){
32758 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32762 leave: function(e, el)
32764 e.preventDefault();
32766 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32770 if(this.bgimage.length && this.html.length){
32771 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32775 onTouchStart: function(e, el)
32777 // e.preventDefault();
32779 this.touchmoved = false;
32781 if(!this.isFitContainer){
32785 if(!this.bgimage.length || !this.html.length){
32789 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32791 this.timer = new Date().getTime();
32795 onTouchMove: function(e, el)
32797 this.touchmoved = true;
32800 onContextMenu : function(e,el)
32802 e.preventDefault();
32803 e.stopPropagation();
32807 onTouchEnd: function(e, el)
32809 // e.preventDefault();
32811 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32818 if(!this.bgimage.length || !this.html.length){
32820 if(this.href.length){
32821 window.location.href = this.href;
32827 if(!this.isFitContainer){
32831 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32833 window.location.href = this.href;
32836 //selection on single brick only
32837 selectBrick : function() {
32839 if (!this.parentId) {
32843 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32844 var index = m.selectedBrick.indexOf(this.id);
32847 m.selectedBrick.splice(index,1);
32848 this.el.removeClass(this.activeClass);
32852 for(var i = 0; i < m.selectedBrick.length; i++) {
32853 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32854 b.el.removeClass(b.activeClass);
32857 m.selectedBrick = [];
32859 m.selectedBrick.push(this.id);
32860 this.el.addClass(this.activeClass);
32866 Roo.apply(Roo.bootstrap.MasonryBrick, {
32869 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32871 * register a Masonry Brick
32872 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32875 register : function(brick)
32877 //this.groups[brick.id] = brick;
32878 this.groups.add(brick.id, brick);
32881 * fetch a masonry brick based on the masonry brick ID
32882 * @param {string} the masonry brick to add
32883 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32886 get: function(brick_id)
32888 // if (typeof(this.groups[brick_id]) == 'undefined') {
32891 // return this.groups[brick_id] ;
32893 if(this.groups.key(brick_id)) {
32894 return this.groups.key(brick_id);
32912 * @class Roo.bootstrap.Brick
32913 * @extends Roo.bootstrap.Component
32914 * Bootstrap Brick class
32917 * Create a new Brick
32918 * @param {Object} config The config object
32921 Roo.bootstrap.Brick = function(config){
32922 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32928 * When a Brick is click
32929 * @param {Roo.bootstrap.Brick} this
32930 * @param {Roo.EventObject} e
32936 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32939 * @cfg {String} title
32943 * @cfg {String} html
32947 * @cfg {String} bgimage
32951 * @cfg {String} cls
32955 * @cfg {String} href
32959 * @cfg {String} video
32963 * @cfg {Boolean} square
32967 getAutoCreate : function()
32969 var cls = 'roo-brick';
32971 if(this.href.length){
32972 cls += ' roo-brick-link';
32975 if(this.bgimage.length){
32976 cls += ' roo-brick-image';
32979 if(!this.html.length && !this.bgimage.length){
32980 cls += ' roo-brick-center-title';
32983 if(!this.html.length && this.bgimage.length){
32984 cls += ' roo-brick-bottom-title';
32988 cls += ' ' + this.cls;
32992 tag: (this.href.length) ? 'a' : 'div',
32997 cls: 'roo-brick-paragraph',
33003 if(this.href.length){
33004 cfg.href = this.href;
33007 var cn = cfg.cn[0].cn;
33009 if(this.title.length){
33012 cls: 'roo-brick-title',
33017 if(this.html.length){
33020 cls: 'roo-brick-text',
33027 if(this.bgimage.length){
33030 cls: 'roo-brick-image-view',
33038 initEvents: function()
33040 if(this.title.length || this.html.length){
33041 this.el.on('mouseenter' ,this.enter, this);
33042 this.el.on('mouseleave', this.leave, this);
33045 Roo.EventManager.onWindowResize(this.resize, this);
33047 if(this.bgimage.length){
33048 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33049 this.imageEl.on('load', this.onImageLoad, this);
33056 onImageLoad : function()
33061 resize : function()
33063 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33065 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33067 if(this.bgimage.length){
33068 var image = this.el.select('.roo-brick-image-view', true).first();
33070 image.setWidth(paragraph.getWidth());
33073 image.setHeight(paragraph.getWidth());
33076 this.el.setHeight(image.getHeight());
33077 paragraph.setHeight(image.getHeight());
33083 enter: function(e, el)
33085 e.preventDefault();
33087 if(this.bgimage.length){
33088 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33089 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33093 leave: function(e, el)
33095 e.preventDefault();
33097 if(this.bgimage.length){
33098 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33099 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33114 * @class Roo.bootstrap.NumberField
33115 * @extends Roo.bootstrap.Input
33116 * Bootstrap NumberField class
33122 * Create a new NumberField
33123 * @param {Object} config The config object
33126 Roo.bootstrap.NumberField = function(config){
33127 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33130 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33133 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33135 allowDecimals : true,
33137 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33139 decimalSeparator : ".",
33141 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33143 decimalPrecision : 2,
33145 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33147 allowNegative : true,
33150 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33154 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33156 minValue : Number.NEGATIVE_INFINITY,
33158 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33160 maxValue : Number.MAX_VALUE,
33162 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33164 minText : "The minimum value for this field is {0}",
33166 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33168 maxText : "The maximum value for this field is {0}",
33170 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33171 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33173 nanText : "{0} is not a valid number",
33175 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33179 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33181 thousandsDelimiter : false,
33183 * @cfg {String} valueAlign alignment of value
33185 valueAlign : "left",
33187 getAutoCreate : function()
33189 var hiddenInput = {
33193 cls: 'hidden-number-input'
33197 hiddenInput.name = this.name;
33202 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33204 this.name = hiddenInput.name;
33206 if(cfg.cn.length > 0) {
33207 cfg.cn.push(hiddenInput);
33214 initEvents : function()
33216 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33218 var allowed = "0123456789";
33220 if(this.allowDecimals){
33221 allowed += this.decimalSeparator;
33224 if(this.allowNegative){
33228 if(this.thousandsDelimiter) {
33232 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33234 var keyPress = function(e){
33236 var k = e.getKey();
33238 var c = e.getCharCode();
33241 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33242 allowed.indexOf(String.fromCharCode(c)) === -1
33248 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33252 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33257 this.el.on("keypress", keyPress, this);
33260 validateValue : function(value)
33263 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33267 var num = this.parseValue(value);
33270 this.markInvalid(String.format(this.nanText, value));
33274 if(num < this.minValue){
33275 this.markInvalid(String.format(this.minText, this.minValue));
33279 if(num > this.maxValue){
33280 this.markInvalid(String.format(this.maxText, this.maxValue));
33287 getValue : function()
33289 var v = this.hiddenEl().getValue();
33291 return this.fixPrecision(this.parseValue(v));
33294 parseValue : function(value)
33296 if(this.thousandsDelimiter) {
33298 r = new RegExp(",", "g");
33299 value = value.replace(r, "");
33302 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33303 return isNaN(value) ? '' : value;
33306 fixPrecision : function(value)
33308 if(this.thousandsDelimiter) {
33310 r = new RegExp(",", "g");
33311 value = value.replace(r, "");
33314 var nan = isNaN(value);
33316 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33317 return nan ? '' : value;
33319 return parseFloat(value).toFixed(this.decimalPrecision);
33322 setValue : function(v)
33324 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33330 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33332 this.inputEl().dom.value = (v == '') ? '' :
33333 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33335 if(!this.allowZero && v === '0') {
33336 this.hiddenEl().dom.value = '';
33337 this.inputEl().dom.value = '';
33344 decimalPrecisionFcn : function(v)
33346 return Math.floor(v);
33349 beforeBlur : function()
33355 var v = this.parseValue(this.getRawValue());
33362 hiddenEl : function()
33364 return this.el.select('input.hidden-number-input',true).first();
33376 * @class Roo.bootstrap.DocumentSlider
33377 * @extends Roo.bootstrap.Component
33378 * Bootstrap DocumentSlider class
33381 * Create a new DocumentViewer
33382 * @param {Object} config The config object
33385 Roo.bootstrap.DocumentSlider = function(config){
33386 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33393 * Fire after initEvent
33394 * @param {Roo.bootstrap.DocumentSlider} this
33399 * Fire after update
33400 * @param {Roo.bootstrap.DocumentSlider} this
33406 * @param {Roo.bootstrap.DocumentSlider} this
33412 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33418 getAutoCreate : function()
33422 cls : 'roo-document-slider',
33426 cls : 'roo-document-slider-header',
33430 cls : 'roo-document-slider-header-title'
33436 cls : 'roo-document-slider-body',
33440 cls : 'roo-document-slider-prev',
33444 cls : 'fa fa-chevron-left'
33450 cls : 'roo-document-slider-thumb',
33454 cls : 'roo-document-slider-image'
33460 cls : 'roo-document-slider-next',
33464 cls : 'fa fa-chevron-right'
33476 initEvents : function()
33478 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33479 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33481 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33482 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33484 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33485 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33487 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33488 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33490 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33491 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33493 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33494 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33496 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33497 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33499 this.thumbEl.on('click', this.onClick, this);
33501 this.prevIndicator.on('click', this.prev, this);
33503 this.nextIndicator.on('click', this.next, this);
33507 initial : function()
33509 if(this.files.length){
33510 this.indicator = 1;
33514 this.fireEvent('initial', this);
33517 update : function()
33519 this.imageEl.attr('src', this.files[this.indicator - 1]);
33521 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33523 this.prevIndicator.show();
33525 if(this.indicator == 1){
33526 this.prevIndicator.hide();
33529 this.nextIndicator.show();
33531 if(this.indicator == this.files.length){
33532 this.nextIndicator.hide();
33535 this.thumbEl.scrollTo('top');
33537 this.fireEvent('update', this);
33540 onClick : function(e)
33542 e.preventDefault();
33544 this.fireEvent('click', this);
33549 e.preventDefault();
33551 this.indicator = Math.max(1, this.indicator - 1);
33558 e.preventDefault();
33560 this.indicator = Math.min(this.files.length, this.indicator + 1);
33574 * @class Roo.bootstrap.RadioSet
33575 * @extends Roo.bootstrap.Input
33576 * Bootstrap RadioSet class
33577 * @cfg {String} indicatorpos (left|right) default left
33578 * @cfg {Boolean} inline (true|false) inline the element (default true)
33579 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33581 * Create a new RadioSet
33582 * @param {Object} config The config object
33585 Roo.bootstrap.RadioSet = function(config){
33587 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33591 Roo.bootstrap.RadioSet.register(this);
33596 * Fires when the element is checked or unchecked.
33597 * @param {Roo.bootstrap.RadioSet} this This radio
33598 * @param {Roo.bootstrap.Radio} item The checked item
33603 * Fires when the element is click.
33604 * @param {Roo.bootstrap.RadioSet} this This radio set
33605 * @param {Roo.bootstrap.Radio} item The checked item
33606 * @param {Roo.EventObject} e The event object
33613 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33621 indicatorpos : 'left',
33623 getAutoCreate : function()
33627 cls : 'roo-radio-set-label',
33631 html : this.fieldLabel
33636 if(this.indicatorpos == 'left'){
33639 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33640 tooltip : 'This field is required'
33645 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33646 tooltip : 'This field is required'
33652 cls : 'roo-radio-set-items'
33655 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33657 if (align === 'left' && this.fieldLabel.length) {
33660 cls : "roo-radio-set-right",
33666 if(this.labelWidth > 12){
33667 label.style = "width: " + this.labelWidth + 'px';
33670 if(this.labelWidth < 13 && this.labelmd == 0){
33671 this.labelmd = this.labelWidth;
33674 if(this.labellg > 0){
33675 label.cls += ' col-lg-' + this.labellg;
33676 items.cls += ' col-lg-' + (12 - this.labellg);
33679 if(this.labelmd > 0){
33680 label.cls += ' col-md-' + this.labelmd;
33681 items.cls += ' col-md-' + (12 - this.labelmd);
33684 if(this.labelsm > 0){
33685 label.cls += ' col-sm-' + this.labelsm;
33686 items.cls += ' col-sm-' + (12 - this.labelsm);
33689 if(this.labelxs > 0){
33690 label.cls += ' col-xs-' + this.labelxs;
33691 items.cls += ' col-xs-' + (12 - this.labelxs);
33697 cls : 'roo-radio-set',
33701 cls : 'roo-radio-set-input',
33704 value : this.value ? this.value : ''
33711 if(this.weight.length){
33712 cfg.cls += ' roo-radio-' + this.weight;
33716 cfg.cls += ' roo-radio-set-inline';
33720 ['xs','sm','md','lg'].map(function(size){
33721 if (settings[size]) {
33722 cfg.cls += ' col-' + size + '-' + settings[size];
33730 initEvents : function()
33732 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33733 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33735 if(!this.fieldLabel.length){
33736 this.labelEl.hide();
33739 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33740 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33742 this.indicatorEl().addClass('invisible');
33744 this.originalValue = this.getValue();
33748 inputEl: function ()
33750 return this.el.select('.roo-radio-set-input', true).first();
33753 getChildContainer : function()
33755 return this.itemsEl;
33758 register : function(item)
33760 this.radioes.push(item);
33764 validate : function()
33766 if(this.getEl().hasClass('hidden')){
33772 Roo.each(this.radioes, function(i){
33781 if(this.allowBlank) {
33785 if(this.disabled || valid){
33790 this.markInvalid();
33795 markValid : function()
33797 if(this.labelEl.isVisible(true)){
33798 this.indicatorEl().removeClass('visible');
33799 this.indicatorEl().addClass('invisible');
33802 this.el.removeClass([this.invalidClass, this.validClass]);
33803 this.el.addClass(this.validClass);
33805 this.fireEvent('valid', this);
33808 markInvalid : function(msg)
33810 if(this.allowBlank || this.disabled){
33814 if(this.labelEl.isVisible(true)){
33815 this.indicatorEl().removeClass('invisible');
33816 this.indicatorEl().addClass('visible');
33819 this.el.removeClass([this.invalidClass, this.validClass]);
33820 this.el.addClass(this.invalidClass);
33822 this.fireEvent('invalid', this, msg);
33826 setValue : function(v, suppressEvent)
33828 if(this.value === v){
33835 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33838 Roo.each(this.radioes, function(i){
33840 i.el.removeClass('checked');
33843 Roo.each(this.radioes, function(i){
33845 if(i.value === v || i.value.toString() === v.toString()){
33847 i.el.addClass('checked');
33849 if(suppressEvent !== true){
33850 this.fireEvent('check', this, i);
33861 clearInvalid : function(){
33863 if(!this.el || this.preventMark){
33867 this.el.removeClass([this.invalidClass]);
33869 this.fireEvent('valid', this);
33874 Roo.apply(Roo.bootstrap.RadioSet, {
33878 register : function(set)
33880 this.groups[set.name] = set;
33883 get: function(name)
33885 if (typeof(this.groups[name]) == 'undefined') {
33889 return this.groups[name] ;
33895 * Ext JS Library 1.1.1
33896 * Copyright(c) 2006-2007, Ext JS, LLC.
33898 * Originally Released Under LGPL - original licence link has changed is not relivant.
33901 * <script type="text/javascript">
33906 * @class Roo.bootstrap.SplitBar
33907 * @extends Roo.util.Observable
33908 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33912 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33913 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33914 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33915 split.minSize = 100;
33916 split.maxSize = 600;
33917 split.animate = true;
33918 split.on('moved', splitterMoved);
33921 * Create a new SplitBar
33922 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33923 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33924 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33925 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33926 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33927 position of the SplitBar).
33929 Roo.bootstrap.SplitBar = function(cfg){
33934 // dragElement : elm
33935 // resizingElement: el,
33937 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33938 // placement : Roo.bootstrap.SplitBar.LEFT ,
33939 // existingProxy ???
33942 this.el = Roo.get(cfg.dragElement, true);
33943 this.el.dom.unselectable = "on";
33945 this.resizingEl = Roo.get(cfg.resizingElement, true);
33949 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33950 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33953 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33956 * The minimum size of the resizing element. (Defaults to 0)
33962 * The maximum size of the resizing element. (Defaults to 2000)
33965 this.maxSize = 2000;
33968 * Whether to animate the transition to the new size
33971 this.animate = false;
33974 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33977 this.useShim = false;
33982 if(!cfg.existingProxy){
33984 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
33986 this.proxy = Roo.get(cfg.existingProxy).dom;
33989 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
33992 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
33995 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
33998 this.dragSpecs = {};
34001 * @private The adapter to use to positon and resize elements
34003 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34004 this.adapter.init(this);
34006 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34008 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34009 this.el.addClass("roo-splitbar-h");
34012 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34013 this.el.addClass("roo-splitbar-v");
34019 * Fires when the splitter is moved (alias for {@link #event-moved})
34020 * @param {Roo.bootstrap.SplitBar} this
34021 * @param {Number} newSize the new width or height
34026 * Fires when the splitter is moved
34027 * @param {Roo.bootstrap.SplitBar} this
34028 * @param {Number} newSize the new width or height
34032 * @event beforeresize
34033 * Fires before the splitter is dragged
34034 * @param {Roo.bootstrap.SplitBar} this
34036 "beforeresize" : true,
34038 "beforeapply" : true
34041 Roo.util.Observable.call(this);
34044 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34045 onStartProxyDrag : function(x, y){
34046 this.fireEvent("beforeresize", this);
34048 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34050 o.enableDisplayMode("block");
34051 // all splitbars share the same overlay
34052 Roo.bootstrap.SplitBar.prototype.overlay = o;
34054 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34055 this.overlay.show();
34056 Roo.get(this.proxy).setDisplayed("block");
34057 var size = this.adapter.getElementSize(this);
34058 this.activeMinSize = this.getMinimumSize();;
34059 this.activeMaxSize = this.getMaximumSize();;
34060 var c1 = size - this.activeMinSize;
34061 var c2 = Math.max(this.activeMaxSize - size, 0);
34062 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34063 this.dd.resetConstraints();
34064 this.dd.setXConstraint(
34065 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34066 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34068 this.dd.setYConstraint(0, 0);
34070 this.dd.resetConstraints();
34071 this.dd.setXConstraint(0, 0);
34072 this.dd.setYConstraint(
34073 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34074 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34077 this.dragSpecs.startSize = size;
34078 this.dragSpecs.startPoint = [x, y];
34079 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34083 * @private Called after the drag operation by the DDProxy
34085 onEndProxyDrag : function(e){
34086 Roo.get(this.proxy).setDisplayed(false);
34087 var endPoint = Roo.lib.Event.getXY(e);
34089 this.overlay.hide();
34092 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34093 newSize = this.dragSpecs.startSize +
34094 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34095 endPoint[0] - this.dragSpecs.startPoint[0] :
34096 this.dragSpecs.startPoint[0] - endPoint[0]
34099 newSize = this.dragSpecs.startSize +
34100 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34101 endPoint[1] - this.dragSpecs.startPoint[1] :
34102 this.dragSpecs.startPoint[1] - endPoint[1]
34105 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34106 if(newSize != this.dragSpecs.startSize){
34107 if(this.fireEvent('beforeapply', this, newSize) !== false){
34108 this.adapter.setElementSize(this, newSize);
34109 this.fireEvent("moved", this, newSize);
34110 this.fireEvent("resize", this, newSize);
34116 * Get the adapter this SplitBar uses
34117 * @return The adapter object
34119 getAdapter : function(){
34120 return this.adapter;
34124 * Set the adapter this SplitBar uses
34125 * @param {Object} adapter A SplitBar adapter object
34127 setAdapter : function(adapter){
34128 this.adapter = adapter;
34129 this.adapter.init(this);
34133 * Gets the minimum size for the resizing element
34134 * @return {Number} The minimum size
34136 getMinimumSize : function(){
34137 return this.minSize;
34141 * Sets the minimum size for the resizing element
34142 * @param {Number} minSize The minimum size
34144 setMinimumSize : function(minSize){
34145 this.minSize = minSize;
34149 * Gets the maximum size for the resizing element
34150 * @return {Number} The maximum size
34152 getMaximumSize : function(){
34153 return this.maxSize;
34157 * Sets the maximum size for the resizing element
34158 * @param {Number} maxSize The maximum size
34160 setMaximumSize : function(maxSize){
34161 this.maxSize = maxSize;
34165 * Sets the initialize size for the resizing element
34166 * @param {Number} size The initial size
34168 setCurrentSize : function(size){
34169 var oldAnimate = this.animate;
34170 this.animate = false;
34171 this.adapter.setElementSize(this, size);
34172 this.animate = oldAnimate;
34176 * Destroy this splitbar.
34177 * @param {Boolean} removeEl True to remove the element
34179 destroy : function(removeEl){
34181 this.shim.remove();
34184 this.proxy.parentNode.removeChild(this.proxy);
34192 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
34194 Roo.bootstrap.SplitBar.createProxy = function(dir){
34195 var proxy = new Roo.Element(document.createElement("div"));
34196 proxy.unselectable();
34197 var cls = 'roo-splitbar-proxy';
34198 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34199 document.body.appendChild(proxy.dom);
34204 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34205 * Default Adapter. It assumes the splitter and resizing element are not positioned
34206 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34208 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34211 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34212 // do nothing for now
34213 init : function(s){
34217 * Called before drag operations to get the current size of the resizing element.
34218 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34220 getElementSize : function(s){
34221 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34222 return s.resizingEl.getWidth();
34224 return s.resizingEl.getHeight();
34229 * Called after drag operations to set the size of the resizing element.
34230 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34231 * @param {Number} newSize The new size to set
34232 * @param {Function} onComplete A function to be invoked when resizing is complete
34234 setElementSize : function(s, newSize, onComplete){
34235 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34237 s.resizingEl.setWidth(newSize);
34239 onComplete(s, newSize);
34242 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34247 s.resizingEl.setHeight(newSize);
34249 onComplete(s, newSize);
34252 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34259 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34260 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34261 * Adapter that moves the splitter element to align with the resized sizing element.
34262 * Used with an absolute positioned SplitBar.
34263 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34264 * document.body, make sure you assign an id to the body element.
34266 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34267 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34268 this.container = Roo.get(container);
34271 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34272 init : function(s){
34273 this.basic.init(s);
34276 getElementSize : function(s){
34277 return this.basic.getElementSize(s);
34280 setElementSize : function(s, newSize, onComplete){
34281 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34284 moveSplitter : function(s){
34285 var yes = Roo.bootstrap.SplitBar;
34286 switch(s.placement){
34288 s.el.setX(s.resizingEl.getRight());
34291 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34294 s.el.setY(s.resizingEl.getBottom());
34297 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34304 * Orientation constant - Create a vertical SplitBar
34308 Roo.bootstrap.SplitBar.VERTICAL = 1;
34311 * Orientation constant - Create a horizontal SplitBar
34315 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34318 * Placement constant - The resizing element is to the left of the splitter element
34322 Roo.bootstrap.SplitBar.LEFT = 1;
34325 * Placement constant - The resizing element is to the right of the splitter element
34329 Roo.bootstrap.SplitBar.RIGHT = 2;
34332 * Placement constant - The resizing element is positioned above the splitter element
34336 Roo.bootstrap.SplitBar.TOP = 3;
34339 * Placement constant - The resizing element is positioned under splitter element
34343 Roo.bootstrap.SplitBar.BOTTOM = 4;
34344 Roo.namespace("Roo.bootstrap.layout");/*
34346 * Ext JS Library 1.1.1
34347 * Copyright(c) 2006-2007, Ext JS, LLC.
34349 * Originally Released Under LGPL - original licence link has changed is not relivant.
34352 * <script type="text/javascript">
34356 * @class Roo.bootstrap.layout.Manager
34357 * @extends Roo.bootstrap.Component
34358 * Base class for layout managers.
34360 Roo.bootstrap.layout.Manager = function(config)
34362 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34368 /** false to disable window resize monitoring @type Boolean */
34369 this.monitorWindowResize = true;
34374 * Fires when a layout is performed.
34375 * @param {Roo.LayoutManager} this
34379 * @event regionresized
34380 * Fires when the user resizes a region.
34381 * @param {Roo.LayoutRegion} region The resized region
34382 * @param {Number} newSize The new size (width for east/west, height for north/south)
34384 "regionresized" : true,
34386 * @event regioncollapsed
34387 * Fires when a region is collapsed.
34388 * @param {Roo.LayoutRegion} region The collapsed region
34390 "regioncollapsed" : true,
34392 * @event regionexpanded
34393 * Fires when a region is expanded.
34394 * @param {Roo.LayoutRegion} region The expanded region
34396 "regionexpanded" : true
34398 this.updating = false;
34401 this.el = Roo.get(config.el);
34407 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34412 monitorWindowResize : true,
34418 onRender : function(ct, position)
34421 this.el = Roo.get(ct);
34424 //this.fireEvent('render',this);
34428 initEvents: function()
34432 // ie scrollbar fix
34433 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34434 document.body.scroll = "no";
34435 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34436 this.el.position('relative');
34438 this.id = this.el.id;
34439 this.el.addClass("roo-layout-container");
34440 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34441 if(this.el.dom != document.body ) {
34442 this.el.on('resize', this.layout,this);
34443 this.el.on('show', this.layout,this);
34449 * Returns true if this layout is currently being updated
34450 * @return {Boolean}
34452 isUpdating : function(){
34453 return this.updating;
34457 * Suspend the LayoutManager from doing auto-layouts while
34458 * making multiple add or remove calls
34460 beginUpdate : function(){
34461 this.updating = true;
34465 * Restore auto-layouts and optionally disable the manager from performing a layout
34466 * @param {Boolean} noLayout true to disable a layout update
34468 endUpdate : function(noLayout){
34469 this.updating = false;
34475 layout: function(){
34479 onRegionResized : function(region, newSize){
34480 this.fireEvent("regionresized", region, newSize);
34484 onRegionCollapsed : function(region){
34485 this.fireEvent("regioncollapsed", region);
34488 onRegionExpanded : function(region){
34489 this.fireEvent("regionexpanded", region);
34493 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34494 * performs box-model adjustments.
34495 * @return {Object} The size as an object {width: (the width), height: (the height)}
34497 getViewSize : function()
34500 if(this.el.dom != document.body){
34501 size = this.el.getSize();
34503 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34505 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34506 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34511 * Returns the Element this layout is bound to.
34512 * @return {Roo.Element}
34514 getEl : function(){
34519 * Returns the specified region.
34520 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34521 * @return {Roo.LayoutRegion}
34523 getRegion : function(target){
34524 return this.regions[target.toLowerCase()];
34527 onWindowResize : function(){
34528 if(this.monitorWindowResize){
34535 * Ext JS Library 1.1.1
34536 * Copyright(c) 2006-2007, Ext JS, LLC.
34538 * Originally Released Under LGPL - original licence link has changed is not relivant.
34541 * <script type="text/javascript">
34544 * @class Roo.bootstrap.layout.Border
34545 * @extends Roo.bootstrap.layout.Manager
34546 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34547 * please see: examples/bootstrap/nested.html<br><br>
34549 <b>The container the layout is rendered into can be either the body element or any other element.
34550 If it is not the body element, the container needs to either be an absolute positioned element,
34551 or you will need to add "position:relative" to the css of the container. You will also need to specify
34552 the container size if it is not the body element.</b>
34555 * Create a new Border
34556 * @param {Object} config Configuration options
34558 Roo.bootstrap.layout.Border = function(config){
34559 config = config || {};
34560 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34564 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34565 if(config[region]){
34566 config[region].region = region;
34567 this.addRegion(config[region]);
34573 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34575 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34577 * Creates and adds a new region if it doesn't already exist.
34578 * @param {String} target The target region key (north, south, east, west or center).
34579 * @param {Object} config The regions config object
34580 * @return {BorderLayoutRegion} The new region
34582 addRegion : function(config)
34584 if(!this.regions[config.region]){
34585 var r = this.factory(config);
34586 this.bindRegion(r);
34588 return this.regions[config.region];
34592 bindRegion : function(r){
34593 this.regions[r.config.region] = r;
34595 r.on("visibilitychange", this.layout, this);
34596 r.on("paneladded", this.layout, this);
34597 r.on("panelremoved", this.layout, this);
34598 r.on("invalidated", this.layout, this);
34599 r.on("resized", this.onRegionResized, this);
34600 r.on("collapsed", this.onRegionCollapsed, this);
34601 r.on("expanded", this.onRegionExpanded, this);
34605 * Performs a layout update.
34607 layout : function()
34609 if(this.updating) {
34613 // render all the rebions if they have not been done alreayd?
34614 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34615 if(this.regions[region] && !this.regions[region].bodyEl){
34616 this.regions[region].onRender(this.el)
34620 var size = this.getViewSize();
34621 var w = size.width;
34622 var h = size.height;
34627 //var x = 0, y = 0;
34629 var rs = this.regions;
34630 var north = rs["north"];
34631 var south = rs["south"];
34632 var west = rs["west"];
34633 var east = rs["east"];
34634 var center = rs["center"];
34635 //if(this.hideOnLayout){ // not supported anymore
34636 //c.el.setStyle("display", "none");
34638 if(north && north.isVisible()){
34639 var b = north.getBox();
34640 var m = north.getMargins();
34641 b.width = w - (m.left+m.right);
34644 centerY = b.height + b.y + m.bottom;
34645 centerH -= centerY;
34646 north.updateBox(this.safeBox(b));
34648 if(south && south.isVisible()){
34649 var b = south.getBox();
34650 var m = south.getMargins();
34651 b.width = w - (m.left+m.right);
34653 var totalHeight = (b.height + m.top + m.bottom);
34654 b.y = h - totalHeight + m.top;
34655 centerH -= totalHeight;
34656 south.updateBox(this.safeBox(b));
34658 if(west && west.isVisible()){
34659 var b = west.getBox();
34660 var m = west.getMargins();
34661 b.height = centerH - (m.top+m.bottom);
34663 b.y = centerY + m.top;
34664 var totalWidth = (b.width + m.left + m.right);
34665 centerX += totalWidth;
34666 centerW -= totalWidth;
34667 west.updateBox(this.safeBox(b));
34669 if(east && east.isVisible()){
34670 var b = east.getBox();
34671 var m = east.getMargins();
34672 b.height = centerH - (m.top+m.bottom);
34673 var totalWidth = (b.width + m.left + m.right);
34674 b.x = w - totalWidth + m.left;
34675 b.y = centerY + m.top;
34676 centerW -= totalWidth;
34677 east.updateBox(this.safeBox(b));
34680 var m = center.getMargins();
34682 x: centerX + m.left,
34683 y: centerY + m.top,
34684 width: centerW - (m.left+m.right),
34685 height: centerH - (m.top+m.bottom)
34687 //if(this.hideOnLayout){
34688 //center.el.setStyle("display", "block");
34690 center.updateBox(this.safeBox(centerBox));
34693 this.fireEvent("layout", this);
34697 safeBox : function(box){
34698 box.width = Math.max(0, box.width);
34699 box.height = Math.max(0, box.height);
34704 * Adds a ContentPanel (or subclass) to this layout.
34705 * @param {String} target The target region key (north, south, east, west or center).
34706 * @param {Roo.ContentPanel} panel The panel to add
34707 * @return {Roo.ContentPanel} The added panel
34709 add : function(target, panel){
34711 target = target.toLowerCase();
34712 return this.regions[target].add(panel);
34716 * Remove a ContentPanel (or subclass) to this layout.
34717 * @param {String} target The target region key (north, south, east, west or center).
34718 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34719 * @return {Roo.ContentPanel} The removed panel
34721 remove : function(target, panel){
34722 target = target.toLowerCase();
34723 return this.regions[target].remove(panel);
34727 * Searches all regions for a panel with the specified id
34728 * @param {String} panelId
34729 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34731 findPanel : function(panelId){
34732 var rs = this.regions;
34733 for(var target in rs){
34734 if(typeof rs[target] != "function"){
34735 var p = rs[target].getPanel(panelId);
34745 * Searches all regions for a panel with the specified id and activates (shows) it.
34746 * @param {String/ContentPanel} panelId The panels id or the panel itself
34747 * @return {Roo.ContentPanel} The shown panel or null
34749 showPanel : function(panelId) {
34750 var rs = this.regions;
34751 for(var target in rs){
34752 var r = rs[target];
34753 if(typeof r != "function"){
34754 if(r.hasPanel(panelId)){
34755 return r.showPanel(panelId);
34763 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34764 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34767 restoreState : function(provider){
34769 provider = Roo.state.Manager;
34771 var sm = new Roo.LayoutStateManager();
34772 sm.init(this, provider);
34778 * Adds a xtype elements to the layout.
34782 xtype : 'ContentPanel',
34789 xtype : 'NestedLayoutPanel',
34795 items : [ ... list of content panels or nested layout panels.. ]
34799 * @param {Object} cfg Xtype definition of item to add.
34801 addxtype : function(cfg)
34803 // basically accepts a pannel...
34804 // can accept a layout region..!?!?
34805 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34808 // theory? children can only be panels??
34810 //if (!cfg.xtype.match(/Panel$/)) {
34815 if (typeof(cfg.region) == 'undefined') {
34816 Roo.log("Failed to add Panel, region was not set");
34820 var region = cfg.region;
34826 xitems = cfg.items;
34833 case 'Content': // ContentPanel (el, cfg)
34834 case 'Scroll': // ContentPanel (el, cfg)
34836 cfg.autoCreate = true;
34837 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34839 // var el = this.el.createChild();
34840 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34843 this.add(region, ret);
34847 case 'TreePanel': // our new panel!
34848 cfg.el = this.el.createChild();
34849 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34850 this.add(region, ret);
34855 // create a new Layout (which is a Border Layout...
34857 var clayout = cfg.layout;
34858 clayout.el = this.el.createChild();
34859 clayout.items = clayout.items || [];
34863 // replace this exitems with the clayout ones..
34864 xitems = clayout.items;
34866 // force background off if it's in center...
34867 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34868 cfg.background = false;
34870 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34873 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34874 //console.log('adding nested layout panel ' + cfg.toSource());
34875 this.add(region, ret);
34876 nb = {}; /// find first...
34881 // needs grid and region
34883 //var el = this.getRegion(region).el.createChild();
34885 *var el = this.el.createChild();
34886 // create the grid first...
34887 cfg.grid.container = el;
34888 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34891 if (region == 'center' && this.active ) {
34892 cfg.background = false;
34895 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34897 this.add(region, ret);
34899 if (cfg.background) {
34900 // render grid on panel activation (if panel background)
34901 ret.on('activate', function(gp) {
34902 if (!gp.grid.rendered) {
34903 // gp.grid.render(el);
34907 // cfg.grid.render(el);
34913 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34914 // it was the old xcomponent building that caused this before.
34915 // espeically if border is the top element in the tree.
34925 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34927 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34928 this.add(region, ret);
34932 throw "Can not add '" + cfg.xtype + "' to Border";
34938 this.beginUpdate();
34942 Roo.each(xitems, function(i) {
34943 region = nb && i.region ? i.region : false;
34945 var add = ret.addxtype(i);
34948 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34949 if (!i.background) {
34950 abn[region] = nb[region] ;
34957 // make the last non-background panel active..
34958 //if (nb) { Roo.log(abn); }
34961 for(var r in abn) {
34962 region = this.getRegion(r);
34964 // tried using nb[r], but it does not work..
34966 region.showPanel(abn[r]);
34977 factory : function(cfg)
34980 var validRegions = Roo.bootstrap.layout.Border.regions;
34982 var target = cfg.region;
34985 var r = Roo.bootstrap.layout;
34989 return new r.North(cfg);
34991 return new r.South(cfg);
34993 return new r.East(cfg);
34995 return new r.West(cfg);
34997 return new r.Center(cfg);
34999 throw 'Layout region "'+target+'" not supported.';
35006 * Ext JS Library 1.1.1
35007 * Copyright(c) 2006-2007, Ext JS, LLC.
35009 * Originally Released Under LGPL - original licence link has changed is not relivant.
35012 * <script type="text/javascript">
35016 * @class Roo.bootstrap.layout.Basic
35017 * @extends Roo.util.Observable
35018 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35019 * and does not have a titlebar, tabs or any other features. All it does is size and position
35020 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35021 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35022 * @cfg {string} region the region that it inhabits..
35023 * @cfg {bool} skipConfig skip config?
35027 Roo.bootstrap.layout.Basic = function(config){
35029 this.mgr = config.mgr;
35031 this.position = config.region;
35033 var skipConfig = config.skipConfig;
35037 * @scope Roo.BasicLayoutRegion
35041 * @event beforeremove
35042 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35043 * @param {Roo.LayoutRegion} this
35044 * @param {Roo.ContentPanel} panel The panel
35045 * @param {Object} e The cancel event object
35047 "beforeremove" : true,
35049 * @event invalidated
35050 * Fires when the layout for this region is changed.
35051 * @param {Roo.LayoutRegion} this
35053 "invalidated" : true,
35055 * @event visibilitychange
35056 * Fires when this region is shown or hidden
35057 * @param {Roo.LayoutRegion} this
35058 * @param {Boolean} visibility true or false
35060 "visibilitychange" : true,
35062 * @event paneladded
35063 * Fires when a panel is added.
35064 * @param {Roo.LayoutRegion} this
35065 * @param {Roo.ContentPanel} panel The panel
35067 "paneladded" : true,
35069 * @event panelremoved
35070 * Fires when a panel is removed.
35071 * @param {Roo.LayoutRegion} this
35072 * @param {Roo.ContentPanel} panel The panel
35074 "panelremoved" : true,
35076 * @event beforecollapse
35077 * Fires when this region before collapse.
35078 * @param {Roo.LayoutRegion} this
35080 "beforecollapse" : true,
35083 * Fires when this region is collapsed.
35084 * @param {Roo.LayoutRegion} this
35086 "collapsed" : true,
35089 * Fires when this region is expanded.
35090 * @param {Roo.LayoutRegion} this
35095 * Fires when this region is slid into view.
35096 * @param {Roo.LayoutRegion} this
35098 "slideshow" : true,
35101 * Fires when this region slides out of view.
35102 * @param {Roo.LayoutRegion} this
35104 "slidehide" : true,
35106 * @event panelactivated
35107 * Fires when a panel is activated.
35108 * @param {Roo.LayoutRegion} this
35109 * @param {Roo.ContentPanel} panel The activated panel
35111 "panelactivated" : true,
35114 * Fires when the user resizes this region.
35115 * @param {Roo.LayoutRegion} this
35116 * @param {Number} newSize The new size (width for east/west, height for north/south)
35120 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35121 this.panels = new Roo.util.MixedCollection();
35122 this.panels.getKey = this.getPanelId.createDelegate(this);
35124 this.activePanel = null;
35125 // ensure listeners are added...
35127 if (config.listeners || config.events) {
35128 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35129 listeners : config.listeners || {},
35130 events : config.events || {}
35134 if(skipConfig !== true){
35135 this.applyConfig(config);
35139 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35141 getPanelId : function(p){
35145 applyConfig : function(config){
35146 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35147 this.config = config;
35152 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35153 * the width, for horizontal (north, south) the height.
35154 * @param {Number} newSize The new width or height
35156 resizeTo : function(newSize){
35157 var el = this.el ? this.el :
35158 (this.activePanel ? this.activePanel.getEl() : null);
35160 switch(this.position){
35163 el.setWidth(newSize);
35164 this.fireEvent("resized", this, newSize);
35168 el.setHeight(newSize);
35169 this.fireEvent("resized", this, newSize);
35175 getBox : function(){
35176 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35179 getMargins : function(){
35180 return this.margins;
35183 updateBox : function(box){
35185 var el = this.activePanel.getEl();
35186 el.dom.style.left = box.x + "px";
35187 el.dom.style.top = box.y + "px";
35188 this.activePanel.setSize(box.width, box.height);
35192 * Returns the container element for this region.
35193 * @return {Roo.Element}
35195 getEl : function(){
35196 return this.activePanel;
35200 * Returns true if this region is currently visible.
35201 * @return {Boolean}
35203 isVisible : function(){
35204 return this.activePanel ? true : false;
35207 setActivePanel : function(panel){
35208 panel = this.getPanel(panel);
35209 if(this.activePanel && this.activePanel != panel){
35210 this.activePanel.setActiveState(false);
35211 this.activePanel.getEl().setLeftTop(-10000,-10000);
35213 this.activePanel = panel;
35214 panel.setActiveState(true);
35216 panel.setSize(this.box.width, this.box.height);
35218 this.fireEvent("panelactivated", this, panel);
35219 this.fireEvent("invalidated");
35223 * Show the specified panel.
35224 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35225 * @return {Roo.ContentPanel} The shown panel or null
35227 showPanel : function(panel){
35228 panel = this.getPanel(panel);
35230 this.setActivePanel(panel);
35236 * Get the active panel for this region.
35237 * @return {Roo.ContentPanel} The active panel or null
35239 getActivePanel : function(){
35240 return this.activePanel;
35244 * Add the passed ContentPanel(s)
35245 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35246 * @return {Roo.ContentPanel} The panel added (if only one was added)
35248 add : function(panel){
35249 if(arguments.length > 1){
35250 for(var i = 0, len = arguments.length; i < len; i++) {
35251 this.add(arguments[i]);
35255 if(this.hasPanel(panel)){
35256 this.showPanel(panel);
35259 var el = panel.getEl();
35260 if(el.dom.parentNode != this.mgr.el.dom){
35261 this.mgr.el.dom.appendChild(el.dom);
35263 if(panel.setRegion){
35264 panel.setRegion(this);
35266 this.panels.add(panel);
35267 el.setStyle("position", "absolute");
35268 if(!panel.background){
35269 this.setActivePanel(panel);
35270 if(this.config.initialSize && this.panels.getCount()==1){
35271 this.resizeTo(this.config.initialSize);
35274 this.fireEvent("paneladded", this, panel);
35279 * Returns true if the panel is in this region.
35280 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35281 * @return {Boolean}
35283 hasPanel : function(panel){
35284 if(typeof panel == "object"){ // must be panel obj
35285 panel = panel.getId();
35287 return this.getPanel(panel) ? true : false;
35291 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35292 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35293 * @param {Boolean} preservePanel Overrides the config preservePanel option
35294 * @return {Roo.ContentPanel} The panel that was removed
35296 remove : function(panel, preservePanel){
35297 panel = this.getPanel(panel);
35302 this.fireEvent("beforeremove", this, panel, e);
35303 if(e.cancel === true){
35306 var panelId = panel.getId();
35307 this.panels.removeKey(panelId);
35312 * Returns the panel specified or null if it's not in this region.
35313 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35314 * @return {Roo.ContentPanel}
35316 getPanel : function(id){
35317 if(typeof id == "object"){ // must be panel obj
35320 return this.panels.get(id);
35324 * Returns this regions position (north/south/east/west/center).
35327 getPosition: function(){
35328 return this.position;
35332 * Ext JS Library 1.1.1
35333 * Copyright(c) 2006-2007, Ext JS, LLC.
35335 * Originally Released Under LGPL - original licence link has changed is not relivant.
35338 * <script type="text/javascript">
35342 * @class Roo.bootstrap.layout.Region
35343 * @extends Roo.bootstrap.layout.Basic
35344 * This class represents a region in a layout manager.
35346 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35347 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
35348 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35349 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35350 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35351 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35352 * @cfg {String} title The title for the region (overrides panel titles)
35353 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35354 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35355 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35356 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35357 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35358 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35359 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35360 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35361 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35362 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35364 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35365 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35366 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35367 * @cfg {Number} width For East/West panels
35368 * @cfg {Number} height For North/South panels
35369 * @cfg {Boolean} split To show the splitter
35370 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35372 * @cfg {string} cls Extra CSS classes to add to region
35374 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35375 * @cfg {string} region the region that it inhabits..
35378 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35379 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35381 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35382 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35383 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35385 Roo.bootstrap.layout.Region = function(config)
35387 this.applyConfig(config);
35389 var mgr = config.mgr;
35390 var pos = config.region;
35391 config.skipConfig = true;
35392 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35395 this.onRender(mgr.el);
35398 this.visible = true;
35399 this.collapsed = false;
35400 this.unrendered_panels = [];
35403 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35405 position: '', // set by wrapper (eg. north/south etc..)
35406 unrendered_panels : null, // unrendered panels.
35407 createBody : function(){
35408 /** This region's body element
35409 * @type Roo.Element */
35410 this.bodyEl = this.el.createChild({
35412 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35416 onRender: function(ctr, pos)
35418 var dh = Roo.DomHelper;
35419 /** This region's container element
35420 * @type Roo.Element */
35421 this.el = dh.append(ctr.dom, {
35423 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35425 /** This region's title element
35426 * @type Roo.Element */
35428 this.titleEl = dh.append(this.el.dom,
35431 unselectable: "on",
35432 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35434 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35435 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35438 this.titleEl.enableDisplayMode();
35439 /** This region's title text element
35440 * @type HTMLElement */
35441 this.titleTextEl = this.titleEl.dom.firstChild;
35442 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35444 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35445 this.closeBtn.enableDisplayMode();
35446 this.closeBtn.on("click", this.closeClicked, this);
35447 this.closeBtn.hide();
35449 this.createBody(this.config);
35450 if(this.config.hideWhenEmpty){
35452 this.on("paneladded", this.validateVisibility, this);
35453 this.on("panelremoved", this.validateVisibility, this);
35455 if(this.autoScroll){
35456 this.bodyEl.setStyle("overflow", "auto");
35458 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35460 //if(c.titlebar !== false){
35461 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35462 this.titleEl.hide();
35464 this.titleEl.show();
35465 if(this.config.title){
35466 this.titleTextEl.innerHTML = this.config.title;
35470 if(this.config.collapsed){
35471 this.collapse(true);
35473 if(this.config.hidden){
35477 if (this.unrendered_panels && this.unrendered_panels.length) {
35478 for (var i =0;i< this.unrendered_panels.length; i++) {
35479 this.add(this.unrendered_panels[i]);
35481 this.unrendered_panels = null;
35487 applyConfig : function(c)
35490 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35491 var dh = Roo.DomHelper;
35492 if(c.titlebar !== false){
35493 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35494 this.collapseBtn.on("click", this.collapse, this);
35495 this.collapseBtn.enableDisplayMode();
35497 if(c.showPin === true || this.showPin){
35498 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35499 this.stickBtn.enableDisplayMode();
35500 this.stickBtn.on("click", this.expand, this);
35501 this.stickBtn.hide();
35506 /** This region's collapsed element
35507 * @type Roo.Element */
35510 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35511 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35514 if(c.floatable !== false){
35515 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35516 this.collapsedEl.on("click", this.collapseClick, this);
35519 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35520 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35521 id: "message", unselectable: "on", style:{"float":"left"}});
35522 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35524 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35525 this.expandBtn.on("click", this.expand, this);
35529 if(this.collapseBtn){
35530 this.collapseBtn.setVisible(c.collapsible == true);
35533 this.cmargins = c.cmargins || this.cmargins ||
35534 (this.position == "west" || this.position == "east" ?
35535 {top: 0, left: 2, right:2, bottom: 0} :
35536 {top: 2, left: 0, right:0, bottom: 2});
35538 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35541 this.bottomTabs = c.tabPosition != "top";
35543 this.autoScroll = c.autoScroll || false;
35548 this.duration = c.duration || .30;
35549 this.slideDuration = c.slideDuration || .45;
35554 * Returns true if this region is currently visible.
35555 * @return {Boolean}
35557 isVisible : function(){
35558 return this.visible;
35562 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35563 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35565 //setCollapsedTitle : function(title){
35566 // title = title || " ";
35567 // if(this.collapsedTitleTextEl){
35568 // this.collapsedTitleTextEl.innerHTML = title;
35572 getBox : function(){
35574 // if(!this.collapsed){
35575 b = this.el.getBox(false, true);
35577 // b = this.collapsedEl.getBox(false, true);
35582 getMargins : function(){
35583 return this.margins;
35584 //return this.collapsed ? this.cmargins : this.margins;
35587 highlight : function(){
35588 this.el.addClass("x-layout-panel-dragover");
35591 unhighlight : function(){
35592 this.el.removeClass("x-layout-panel-dragover");
35595 updateBox : function(box)
35597 if (!this.bodyEl) {
35598 return; // not rendered yet..
35602 if(!this.collapsed){
35603 this.el.dom.style.left = box.x + "px";
35604 this.el.dom.style.top = box.y + "px";
35605 this.updateBody(box.width, box.height);
35607 this.collapsedEl.dom.style.left = box.x + "px";
35608 this.collapsedEl.dom.style.top = box.y + "px";
35609 this.collapsedEl.setSize(box.width, box.height);
35612 this.tabs.autoSizeTabs();
35616 updateBody : function(w, h)
35619 this.el.setWidth(w);
35620 w -= this.el.getBorderWidth("rl");
35621 if(this.config.adjustments){
35622 w += this.config.adjustments[0];
35625 if(h !== null && h > 0){
35626 this.el.setHeight(h);
35627 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35628 h -= this.el.getBorderWidth("tb");
35629 if(this.config.adjustments){
35630 h += this.config.adjustments[1];
35632 this.bodyEl.setHeight(h);
35634 h = this.tabs.syncHeight(h);
35637 if(this.panelSize){
35638 w = w !== null ? w : this.panelSize.width;
35639 h = h !== null ? h : this.panelSize.height;
35641 if(this.activePanel){
35642 var el = this.activePanel.getEl();
35643 w = w !== null ? w : el.getWidth();
35644 h = h !== null ? h : el.getHeight();
35645 this.panelSize = {width: w, height: h};
35646 this.activePanel.setSize(w, h);
35648 if(Roo.isIE && this.tabs){
35649 this.tabs.el.repaint();
35654 * Returns the container element for this region.
35655 * @return {Roo.Element}
35657 getEl : function(){
35662 * Hides this region.
35665 //if(!this.collapsed){
35666 this.el.dom.style.left = "-2000px";
35669 // this.collapsedEl.dom.style.left = "-2000px";
35670 // this.collapsedEl.hide();
35672 this.visible = false;
35673 this.fireEvent("visibilitychange", this, false);
35677 * Shows this region if it was previously hidden.
35680 //if(!this.collapsed){
35683 // this.collapsedEl.show();
35685 this.visible = true;
35686 this.fireEvent("visibilitychange", this, true);
35689 closeClicked : function(){
35690 if(this.activePanel){
35691 this.remove(this.activePanel);
35695 collapseClick : function(e){
35697 e.stopPropagation();
35700 e.stopPropagation();
35706 * Collapses this region.
35707 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35710 collapse : function(skipAnim, skipCheck = false){
35711 if(this.collapsed) {
35715 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35717 this.collapsed = true;
35719 this.split.el.hide();
35721 if(this.config.animate && skipAnim !== true){
35722 this.fireEvent("invalidated", this);
35723 this.animateCollapse();
35725 this.el.setLocation(-20000,-20000);
35727 this.collapsedEl.show();
35728 this.fireEvent("collapsed", this);
35729 this.fireEvent("invalidated", this);
35735 animateCollapse : function(){
35740 * Expands this region if it was previously collapsed.
35741 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35742 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35745 expand : function(e, skipAnim){
35747 e.stopPropagation();
35749 if(!this.collapsed || this.el.hasActiveFx()) {
35753 this.afterSlideIn();
35756 this.collapsed = false;
35757 if(this.config.animate && skipAnim !== true){
35758 this.animateExpand();
35762 this.split.el.show();
35764 this.collapsedEl.setLocation(-2000,-2000);
35765 this.collapsedEl.hide();
35766 this.fireEvent("invalidated", this);
35767 this.fireEvent("expanded", this);
35771 animateExpand : function(){
35775 initTabs : function()
35777 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35779 var ts = new Roo.bootstrap.panel.Tabs({
35780 el: this.bodyEl.dom,
35781 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35782 disableTooltips: this.config.disableTabTips,
35783 toolbar : this.config.toolbar
35786 if(this.config.hideTabs){
35787 ts.stripWrap.setDisplayed(false);
35790 ts.resizeTabs = this.config.resizeTabs === true;
35791 ts.minTabWidth = this.config.minTabWidth || 40;
35792 ts.maxTabWidth = this.config.maxTabWidth || 250;
35793 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35794 ts.monitorResize = false;
35795 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35796 ts.bodyEl.addClass('roo-layout-tabs-body');
35797 this.panels.each(this.initPanelAsTab, this);
35800 initPanelAsTab : function(panel){
35801 var ti = this.tabs.addTab(
35805 this.config.closeOnTab && panel.isClosable(),
35808 if(panel.tabTip !== undefined){
35809 ti.setTooltip(panel.tabTip);
35811 ti.on("activate", function(){
35812 this.setActivePanel(panel);
35815 if(this.config.closeOnTab){
35816 ti.on("beforeclose", function(t, e){
35818 this.remove(panel);
35822 panel.tabItem = ti;
35827 updatePanelTitle : function(panel, title)
35829 if(this.activePanel == panel){
35830 this.updateTitle(title);
35833 var ti = this.tabs.getTab(panel.getEl().id);
35835 if(panel.tabTip !== undefined){
35836 ti.setTooltip(panel.tabTip);
35841 updateTitle : function(title){
35842 if(this.titleTextEl && !this.config.title){
35843 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35847 setActivePanel : function(panel)
35849 panel = this.getPanel(panel);
35850 if(this.activePanel && this.activePanel != panel){
35851 if(this.activePanel.setActiveState(false) === false){
35855 this.activePanel = panel;
35856 panel.setActiveState(true);
35857 if(this.panelSize){
35858 panel.setSize(this.panelSize.width, this.panelSize.height);
35861 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35863 this.updateTitle(panel.getTitle());
35865 this.fireEvent("invalidated", this);
35867 this.fireEvent("panelactivated", this, panel);
35871 * Shows the specified panel.
35872 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35873 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35875 showPanel : function(panel)
35877 panel = this.getPanel(panel);
35880 var tab = this.tabs.getTab(panel.getEl().id);
35881 if(tab.isHidden()){
35882 this.tabs.unhideTab(tab.id);
35886 this.setActivePanel(panel);
35893 * Get the active panel for this region.
35894 * @return {Roo.ContentPanel} The active panel or null
35896 getActivePanel : function(){
35897 return this.activePanel;
35900 validateVisibility : function(){
35901 if(this.panels.getCount() < 1){
35902 this.updateTitle(" ");
35903 this.closeBtn.hide();
35906 if(!this.isVisible()){
35913 * Adds the passed ContentPanel(s) to this region.
35914 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35915 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35917 add : function(panel)
35919 if(arguments.length > 1){
35920 for(var i = 0, len = arguments.length; i < len; i++) {
35921 this.add(arguments[i]);
35926 // if we have not been rendered yet, then we can not really do much of this..
35927 if (!this.bodyEl) {
35928 this.unrendered_panels.push(panel);
35935 if(this.hasPanel(panel)){
35936 this.showPanel(panel);
35939 panel.setRegion(this);
35940 this.panels.add(panel);
35941 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35942 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35943 // and hide them... ???
35944 this.bodyEl.dom.appendChild(panel.getEl().dom);
35945 if(panel.background !== true){
35946 this.setActivePanel(panel);
35948 this.fireEvent("paneladded", this, panel);
35955 this.initPanelAsTab(panel);
35959 if(panel.background !== true){
35960 this.tabs.activate(panel.getEl().id);
35962 this.fireEvent("paneladded", this, panel);
35967 * Hides the tab for the specified panel.
35968 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35970 hidePanel : function(panel){
35971 if(this.tabs && (panel = this.getPanel(panel))){
35972 this.tabs.hideTab(panel.getEl().id);
35977 * Unhides the tab for a previously hidden panel.
35978 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35980 unhidePanel : function(panel){
35981 if(this.tabs && (panel = this.getPanel(panel))){
35982 this.tabs.unhideTab(panel.getEl().id);
35986 clearPanels : function(){
35987 while(this.panels.getCount() > 0){
35988 this.remove(this.panels.first());
35993 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35994 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35995 * @param {Boolean} preservePanel Overrides the config preservePanel option
35996 * @return {Roo.ContentPanel} The panel that was removed
35998 remove : function(panel, preservePanel)
36000 panel = this.getPanel(panel);
36005 this.fireEvent("beforeremove", this, panel, e);
36006 if(e.cancel === true){
36009 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36010 var panelId = panel.getId();
36011 this.panels.removeKey(panelId);
36013 document.body.appendChild(panel.getEl().dom);
36016 this.tabs.removeTab(panel.getEl().id);
36017 }else if (!preservePanel){
36018 this.bodyEl.dom.removeChild(panel.getEl().dom);
36020 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36021 var p = this.panels.first();
36022 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36023 tempEl.appendChild(p.getEl().dom);
36024 this.bodyEl.update("");
36025 this.bodyEl.dom.appendChild(p.getEl().dom);
36027 this.updateTitle(p.getTitle());
36029 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36030 this.setActivePanel(p);
36032 panel.setRegion(null);
36033 if(this.activePanel == panel){
36034 this.activePanel = null;
36036 if(this.config.autoDestroy !== false && preservePanel !== true){
36037 try{panel.destroy();}catch(e){}
36039 this.fireEvent("panelremoved", this, panel);
36044 * Returns the TabPanel component used by this region
36045 * @return {Roo.TabPanel}
36047 getTabs : function(){
36051 createTool : function(parentEl, className){
36052 var btn = Roo.DomHelper.append(parentEl, {
36054 cls: "x-layout-tools-button",
36057 cls: "roo-layout-tools-button-inner " + className,
36061 btn.addClassOnOver("roo-layout-tools-button-over");
36066 * Ext JS Library 1.1.1
36067 * Copyright(c) 2006-2007, Ext JS, LLC.
36069 * Originally Released Under LGPL - original licence link has changed is not relivant.
36072 * <script type="text/javascript">
36078 * @class Roo.SplitLayoutRegion
36079 * @extends Roo.LayoutRegion
36080 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36082 Roo.bootstrap.layout.Split = function(config){
36083 this.cursor = config.cursor;
36084 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36087 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36089 splitTip : "Drag to resize.",
36090 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36091 useSplitTips : false,
36093 applyConfig : function(config){
36094 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36097 onRender : function(ctr,pos) {
36099 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36100 if(!this.config.split){
36105 var splitEl = Roo.DomHelper.append(ctr.dom, {
36107 id: this.el.id + "-split",
36108 cls: "roo-layout-split roo-layout-split-"+this.position,
36111 /** The SplitBar for this region
36112 * @type Roo.SplitBar */
36113 // does not exist yet...
36114 Roo.log([this.position, this.orientation]);
36116 this.split = new Roo.bootstrap.SplitBar({
36117 dragElement : splitEl,
36118 resizingElement: this.el,
36119 orientation : this.orientation
36122 this.split.on("moved", this.onSplitMove, this);
36123 this.split.useShim = this.config.useShim === true;
36124 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36125 if(this.useSplitTips){
36126 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36128 //if(config.collapsible){
36129 // this.split.el.on("dblclick", this.collapse, this);
36132 if(typeof this.config.minSize != "undefined"){
36133 this.split.minSize = this.config.minSize;
36135 if(typeof this.config.maxSize != "undefined"){
36136 this.split.maxSize = this.config.maxSize;
36138 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36139 this.hideSplitter();
36144 getHMaxSize : function(){
36145 var cmax = this.config.maxSize || 10000;
36146 var center = this.mgr.getRegion("center");
36147 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36150 getVMaxSize : function(){
36151 var cmax = this.config.maxSize || 10000;
36152 var center = this.mgr.getRegion("center");
36153 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36156 onSplitMove : function(split, newSize){
36157 this.fireEvent("resized", this, newSize);
36161 * Returns the {@link Roo.SplitBar} for this region.
36162 * @return {Roo.SplitBar}
36164 getSplitBar : function(){
36169 this.hideSplitter();
36170 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36173 hideSplitter : function(){
36175 this.split.el.setLocation(-2000,-2000);
36176 this.split.el.hide();
36182 this.split.el.show();
36184 Roo.bootstrap.layout.Split.superclass.show.call(this);
36187 beforeSlide: function(){
36188 if(Roo.isGecko){// firefox overflow auto bug workaround
36189 this.bodyEl.clip();
36191 this.tabs.bodyEl.clip();
36193 if(this.activePanel){
36194 this.activePanel.getEl().clip();
36196 if(this.activePanel.beforeSlide){
36197 this.activePanel.beforeSlide();
36203 afterSlide : function(){
36204 if(Roo.isGecko){// firefox overflow auto bug workaround
36205 this.bodyEl.unclip();
36207 this.tabs.bodyEl.unclip();
36209 if(this.activePanel){
36210 this.activePanel.getEl().unclip();
36211 if(this.activePanel.afterSlide){
36212 this.activePanel.afterSlide();
36218 initAutoHide : function(){
36219 if(this.autoHide !== false){
36220 if(!this.autoHideHd){
36221 var st = new Roo.util.DelayedTask(this.slideIn, this);
36222 this.autoHideHd = {
36223 "mouseout": function(e){
36224 if(!e.within(this.el, true)){
36228 "mouseover" : function(e){
36234 this.el.on(this.autoHideHd);
36238 clearAutoHide : function(){
36239 if(this.autoHide !== false){
36240 this.el.un("mouseout", this.autoHideHd.mouseout);
36241 this.el.un("mouseover", this.autoHideHd.mouseover);
36245 clearMonitor : function(){
36246 Roo.get(document).un("click", this.slideInIf, this);
36249 // these names are backwards but not changed for compat
36250 slideOut : function(){
36251 if(this.isSlid || this.el.hasActiveFx()){
36254 this.isSlid = true;
36255 if(this.collapseBtn){
36256 this.collapseBtn.hide();
36258 this.closeBtnState = this.closeBtn.getStyle('display');
36259 this.closeBtn.hide();
36261 this.stickBtn.show();
36264 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36265 this.beforeSlide();
36266 this.el.setStyle("z-index", 10001);
36267 this.el.slideIn(this.getSlideAnchor(), {
36268 callback: function(){
36270 this.initAutoHide();
36271 Roo.get(document).on("click", this.slideInIf, this);
36272 this.fireEvent("slideshow", this);
36279 afterSlideIn : function(){
36280 this.clearAutoHide();
36281 this.isSlid = false;
36282 this.clearMonitor();
36283 this.el.setStyle("z-index", "");
36284 if(this.collapseBtn){
36285 this.collapseBtn.show();
36287 this.closeBtn.setStyle('display', this.closeBtnState);
36289 this.stickBtn.hide();
36291 this.fireEvent("slidehide", this);
36294 slideIn : function(cb){
36295 if(!this.isSlid || this.el.hasActiveFx()){
36299 this.isSlid = false;
36300 this.beforeSlide();
36301 this.el.slideOut(this.getSlideAnchor(), {
36302 callback: function(){
36303 this.el.setLeftTop(-10000, -10000);
36305 this.afterSlideIn();
36313 slideInIf : function(e){
36314 if(!e.within(this.el)){
36319 animateCollapse : function(){
36320 this.beforeSlide();
36321 this.el.setStyle("z-index", 20000);
36322 var anchor = this.getSlideAnchor();
36323 this.el.slideOut(anchor, {
36324 callback : function(){
36325 this.el.setStyle("z-index", "");
36326 this.collapsedEl.slideIn(anchor, {duration:.3});
36328 this.el.setLocation(-10000,-10000);
36330 this.fireEvent("collapsed", this);
36337 animateExpand : function(){
36338 this.beforeSlide();
36339 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36340 this.el.setStyle("z-index", 20000);
36341 this.collapsedEl.hide({
36344 this.el.slideIn(this.getSlideAnchor(), {
36345 callback : function(){
36346 this.el.setStyle("z-index", "");
36349 this.split.el.show();
36351 this.fireEvent("invalidated", this);
36352 this.fireEvent("expanded", this);
36380 getAnchor : function(){
36381 return this.anchors[this.position];
36384 getCollapseAnchor : function(){
36385 return this.canchors[this.position];
36388 getSlideAnchor : function(){
36389 return this.sanchors[this.position];
36392 getAlignAdj : function(){
36393 var cm = this.cmargins;
36394 switch(this.position){
36410 getExpandAdj : function(){
36411 var c = this.collapsedEl, cm = this.cmargins;
36412 switch(this.position){
36414 return [-(cm.right+c.getWidth()+cm.left), 0];
36417 return [cm.right+c.getWidth()+cm.left, 0];
36420 return [0, -(cm.top+cm.bottom+c.getHeight())];
36423 return [0, cm.top+cm.bottom+c.getHeight()];
36429 * Ext JS Library 1.1.1
36430 * Copyright(c) 2006-2007, Ext JS, LLC.
36432 * Originally Released Under LGPL - original licence link has changed is not relivant.
36435 * <script type="text/javascript">
36438 * These classes are private internal classes
36440 Roo.bootstrap.layout.Center = function(config){
36441 config.region = "center";
36442 Roo.bootstrap.layout.Region.call(this, config);
36443 this.visible = true;
36444 this.minWidth = config.minWidth || 20;
36445 this.minHeight = config.minHeight || 20;
36448 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36450 // center panel can't be hidden
36454 // center panel can't be hidden
36457 getMinWidth: function(){
36458 return this.minWidth;
36461 getMinHeight: function(){
36462 return this.minHeight;
36475 Roo.bootstrap.layout.North = function(config)
36477 config.region = 'north';
36478 config.cursor = 'n-resize';
36480 Roo.bootstrap.layout.Split.call(this, config);
36484 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36485 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36486 this.split.el.addClass("roo-layout-split-v");
36488 var size = config.initialSize || config.height;
36489 if(typeof size != "undefined"){
36490 this.el.setHeight(size);
36493 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36495 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36499 getBox : function(){
36500 if(this.collapsed){
36501 return this.collapsedEl.getBox();
36503 var box = this.el.getBox();
36505 box.height += this.split.el.getHeight();
36510 updateBox : function(box){
36511 if(this.split && !this.collapsed){
36512 box.height -= this.split.el.getHeight();
36513 this.split.el.setLeft(box.x);
36514 this.split.el.setTop(box.y+box.height);
36515 this.split.el.setWidth(box.width);
36517 if(this.collapsed){
36518 this.updateBody(box.width, null);
36520 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36528 Roo.bootstrap.layout.South = function(config){
36529 config.region = 'south';
36530 config.cursor = 's-resize';
36531 Roo.bootstrap.layout.Split.call(this, config);
36533 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36534 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36535 this.split.el.addClass("roo-layout-split-v");
36537 var size = config.initialSize || config.height;
36538 if(typeof size != "undefined"){
36539 this.el.setHeight(size);
36543 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36544 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36545 getBox : function(){
36546 if(this.collapsed){
36547 return this.collapsedEl.getBox();
36549 var box = this.el.getBox();
36551 var sh = this.split.el.getHeight();
36558 updateBox : function(box){
36559 if(this.split && !this.collapsed){
36560 var sh = this.split.el.getHeight();
36563 this.split.el.setLeft(box.x);
36564 this.split.el.setTop(box.y-sh);
36565 this.split.el.setWidth(box.width);
36567 if(this.collapsed){
36568 this.updateBody(box.width, null);
36570 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36574 Roo.bootstrap.layout.East = function(config){
36575 config.region = "east";
36576 config.cursor = "e-resize";
36577 Roo.bootstrap.layout.Split.call(this, config);
36579 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36580 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36581 this.split.el.addClass("roo-layout-split-h");
36583 var size = config.initialSize || config.width;
36584 if(typeof size != "undefined"){
36585 this.el.setWidth(size);
36588 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36589 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36590 getBox : function(){
36591 if(this.collapsed){
36592 return this.collapsedEl.getBox();
36594 var box = this.el.getBox();
36596 var sw = this.split.el.getWidth();
36603 updateBox : function(box){
36604 if(this.split && !this.collapsed){
36605 var sw = this.split.el.getWidth();
36607 this.split.el.setLeft(box.x);
36608 this.split.el.setTop(box.y);
36609 this.split.el.setHeight(box.height);
36612 if(this.collapsed){
36613 this.updateBody(null, box.height);
36615 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36619 Roo.bootstrap.layout.West = function(config){
36620 config.region = "west";
36621 config.cursor = "w-resize";
36623 Roo.bootstrap.layout.Split.call(this, config);
36625 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36626 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36627 this.split.el.addClass("roo-layout-split-h");
36631 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36632 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36634 onRender: function(ctr, pos)
36636 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36637 var size = this.config.initialSize || this.config.width;
36638 if(typeof size != "undefined"){
36639 this.el.setWidth(size);
36643 getBox : function(){
36644 if(this.collapsed){
36645 return this.collapsedEl.getBox();
36647 var box = this.el.getBox();
36649 box.width += this.split.el.getWidth();
36654 updateBox : function(box){
36655 if(this.split && !this.collapsed){
36656 var sw = this.split.el.getWidth();
36658 this.split.el.setLeft(box.x+box.width);
36659 this.split.el.setTop(box.y);
36660 this.split.el.setHeight(box.height);
36662 if(this.collapsed){
36663 this.updateBody(null, box.height);
36665 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36668 Roo.namespace("Roo.bootstrap.panel");/*
36670 * Ext JS Library 1.1.1
36671 * Copyright(c) 2006-2007, Ext JS, LLC.
36673 * Originally Released Under LGPL - original licence link has changed is not relivant.
36676 * <script type="text/javascript">
36679 * @class Roo.ContentPanel
36680 * @extends Roo.util.Observable
36681 * A basic ContentPanel element.
36682 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36683 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36684 * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
36685 * @cfg {Boolean} closable True if the panel can be closed/removed
36686 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36687 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36688 * @cfg {Toolbar} toolbar A toolbar for this panel
36689 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36690 * @cfg {String} title The title for this panel
36691 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36692 * @cfg {String} url Calls {@link #setUrl} with this value
36693 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36694 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36695 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36696 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36697 * @cfg {Boolean} badges render the badges
36700 * Create a new ContentPanel.
36701 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36702 * @param {String/Object} config A string to set only the title or a config object
36703 * @param {String} content (optional) Set the HTML content for this panel
36704 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36706 Roo.bootstrap.panel.Content = function( config){
36708 this.tpl = config.tpl || false;
36710 var el = config.el;
36711 var content = config.content;
36713 if(config.autoCreate){ // xtype is available if this is called from factory
36716 this.el = Roo.get(el);
36717 if(!this.el && config && config.autoCreate){
36718 if(typeof config.autoCreate == "object"){
36719 if(!config.autoCreate.id){
36720 config.autoCreate.id = config.id||el;
36722 this.el = Roo.DomHelper.append(document.body,
36723 config.autoCreate, true);
36725 var elcfg = { tag: "div",
36726 cls: "roo-layout-inactive-content",
36730 elcfg.html = config.html;
36734 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36737 this.closable = false;
36738 this.loaded = false;
36739 this.active = false;
36742 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36744 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36746 this.wrapEl = this.el; //this.el.wrap();
36748 if (config.toolbar.items) {
36749 ti = config.toolbar.items ;
36750 delete config.toolbar.items ;
36754 this.toolbar.render(this.wrapEl, 'before');
36755 for(var i =0;i < ti.length;i++) {
36756 // Roo.log(['add child', items[i]]);
36757 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36759 this.toolbar.items = nitems;
36760 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36761 delete config.toolbar;
36765 // xtype created footer. - not sure if will work as we normally have to render first..
36766 if (this.footer && !this.footer.el && this.footer.xtype) {
36767 if (!this.wrapEl) {
36768 this.wrapEl = this.el.wrap();
36771 this.footer.container = this.wrapEl.createChild();
36773 this.footer = Roo.factory(this.footer, Roo);
36778 if(typeof config == "string"){
36779 this.title = config;
36781 Roo.apply(this, config);
36785 this.resizeEl = Roo.get(this.resizeEl, true);
36787 this.resizeEl = this.el;
36789 // handle view.xtype
36797 * Fires when this panel is activated.
36798 * @param {Roo.ContentPanel} this
36802 * @event deactivate
36803 * Fires when this panel is activated.
36804 * @param {Roo.ContentPanel} this
36806 "deactivate" : true,
36810 * Fires when this panel is resized if fitToFrame is true.
36811 * @param {Roo.ContentPanel} this
36812 * @param {Number} width The width after any component adjustments
36813 * @param {Number} height The height after any component adjustments
36819 * Fires when this tab is created
36820 * @param {Roo.ContentPanel} this
36831 if(this.autoScroll){
36832 this.resizeEl.setStyle("overflow", "auto");
36834 // fix randome scrolling
36835 //this.el.on('scroll', function() {
36836 // Roo.log('fix random scolling');
36837 // this.scrollTo('top',0);
36840 content = content || this.content;
36842 this.setContent(content);
36844 if(config && config.url){
36845 this.setUrl(this.url, this.params, this.loadOnce);
36850 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36852 if (this.view && typeof(this.view.xtype) != 'undefined') {
36853 this.view.el = this.el.appendChild(document.createElement("div"));
36854 this.view = Roo.factory(this.view);
36855 this.view.render && this.view.render(false, '');
36859 this.fireEvent('render', this);
36862 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36866 setRegion : function(region){
36867 this.region = region;
36868 this.setActiveClass(region && !this.background);
36872 setActiveClass: function(state)
36875 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36876 this.el.setStyle('position','relative');
36878 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36879 this.el.setStyle('position', 'absolute');
36884 * Returns the toolbar for this Panel if one was configured.
36885 * @return {Roo.Toolbar}
36887 getToolbar : function(){
36888 return this.toolbar;
36891 setActiveState : function(active)
36893 this.active = active;
36894 this.setActiveClass(active);
36896 if(this.fireEvent("deactivate", this) === false){
36901 this.fireEvent("activate", this);
36905 * Updates this panel's element
36906 * @param {String} content The new content
36907 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36909 setContent : function(content, loadScripts){
36910 this.el.update(content, loadScripts);
36913 ignoreResize : function(w, h){
36914 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36917 this.lastSize = {width: w, height: h};
36922 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36923 * @return {Roo.UpdateManager} The UpdateManager
36925 getUpdateManager : function(){
36926 return this.el.getUpdateManager();
36929 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36930 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
36933 url: "your-url.php",
36934 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36935 callback: yourFunction,
36936 scope: yourObject, //(optional scope)
36939 text: "Loading...",
36944 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36945 * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
36946 * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
36947 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36948 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
36949 * @return {Roo.ContentPanel} this
36952 var um = this.el.getUpdateManager();
36953 um.update.apply(um, arguments);
36959 * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
36960 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36961 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
36962 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
36963 * @return {Roo.UpdateManager} The UpdateManager
36965 setUrl : function(url, params, loadOnce){
36966 if(this.refreshDelegate){
36967 this.removeListener("activate", this.refreshDelegate);
36969 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36970 this.on("activate", this.refreshDelegate);
36971 return this.el.getUpdateManager();
36974 _handleRefresh : function(url, params, loadOnce){
36975 if(!loadOnce || !this.loaded){
36976 var updater = this.el.getUpdateManager();
36977 updater.update(url, params, this._setLoaded.createDelegate(this));
36981 _setLoaded : function(){
36982 this.loaded = true;
36986 * Returns this panel's id
36989 getId : function(){
36994 * Returns this panel's element - used by regiosn to add.
36995 * @return {Roo.Element}
36997 getEl : function(){
36998 return this.wrapEl || this.el;
37003 adjustForComponents : function(width, height)
37005 //Roo.log('adjustForComponents ');
37006 if(this.resizeEl != this.el){
37007 width -= this.el.getFrameWidth('lr');
37008 height -= this.el.getFrameWidth('tb');
37011 var te = this.toolbar.getEl();
37012 te.setWidth(width);
37013 height -= te.getHeight();
37016 var te = this.footer.getEl();
37017 te.setWidth(width);
37018 height -= te.getHeight();
37022 if(this.adjustments){
37023 width += this.adjustments[0];
37024 height += this.adjustments[1];
37026 return {"width": width, "height": height};
37029 setSize : function(width, height){
37030 if(this.fitToFrame && !this.ignoreResize(width, height)){
37031 if(this.fitContainer && this.resizeEl != this.el){
37032 this.el.setSize(width, height);
37034 var size = this.adjustForComponents(width, height);
37035 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37036 this.fireEvent('resize', this, size.width, size.height);
37041 * Returns this panel's title
37044 getTitle : function(){
37046 if (typeof(this.title) != 'object') {
37051 for (var k in this.title) {
37052 if (!this.title.hasOwnProperty(k)) {
37056 if (k.indexOf('-') >= 0) {
37057 var s = k.split('-');
37058 for (var i = 0; i<s.length; i++) {
37059 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37062 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37069 * Set this panel's title
37070 * @param {String} title
37072 setTitle : function(title){
37073 this.title = title;
37075 this.region.updatePanelTitle(this, title);
37080 * Returns true is this panel was configured to be closable
37081 * @return {Boolean}
37083 isClosable : function(){
37084 return this.closable;
37087 beforeSlide : function(){
37089 this.resizeEl.clip();
37092 afterSlide : function(){
37094 this.resizeEl.unclip();
37098 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37099 * Will fail silently if the {@link #setUrl} method has not been called.
37100 * This does not activate the panel, just updates its content.
37102 refresh : function(){
37103 if(this.refreshDelegate){
37104 this.loaded = false;
37105 this.refreshDelegate();
37110 * Destroys this panel
37112 destroy : function(){
37113 this.el.removeAllListeners();
37114 var tempEl = document.createElement("span");
37115 tempEl.appendChild(this.el.dom);
37116 tempEl.innerHTML = "";
37122 * form - if the content panel contains a form - this is a reference to it.
37123 * @type {Roo.form.Form}
37127 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37128 * This contains a reference to it.
37134 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37144 * @param {Object} cfg Xtype definition of item to add.
37148 getChildContainer: function () {
37149 return this.getEl();
37154 var ret = new Roo.factory(cfg);
37159 if (cfg.xtype.match(/^Form$/)) {
37162 //if (this.footer) {
37163 // el = this.footer.container.insertSibling(false, 'before');
37165 el = this.el.createChild();
37168 this.form = new Roo.form.Form(cfg);
37171 if ( this.form.allItems.length) {
37172 this.form.render(el.dom);
37176 // should only have one of theses..
37177 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37178 // views.. should not be just added - used named prop 'view''
37180 cfg.el = this.el.appendChild(document.createElement("div"));
37183 var ret = new Roo.factory(cfg);
37185 ret.render && ret.render(false, ''); // render blank..
37195 * @class Roo.bootstrap.panel.Grid
37196 * @extends Roo.bootstrap.panel.Content
37198 * Create a new GridPanel.
37199 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37200 * @param {Object} config A the config object
37206 Roo.bootstrap.panel.Grid = function(config)
37210 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37211 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37213 config.el = this.wrapper;
37214 //this.el = this.wrapper;
37216 if (config.container) {
37217 // ctor'ed from a Border/panel.grid
37220 this.wrapper.setStyle("overflow", "hidden");
37221 this.wrapper.addClass('roo-grid-container');
37226 if(config.toolbar){
37227 var tool_el = this.wrapper.createChild();
37228 this.toolbar = Roo.factory(config.toolbar);
37230 if (config.toolbar.items) {
37231 ti = config.toolbar.items ;
37232 delete config.toolbar.items ;
37236 this.toolbar.render(tool_el);
37237 for(var i =0;i < ti.length;i++) {
37238 // Roo.log(['add child', items[i]]);
37239 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37241 this.toolbar.items = nitems;
37243 delete config.toolbar;
37246 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37247 config.grid.scrollBody = true;;
37248 config.grid.monitorWindowResize = false; // turn off autosizing
37249 config.grid.autoHeight = false;
37250 config.grid.autoWidth = false;
37252 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37254 if (config.background) {
37255 // render grid on panel activation (if panel background)
37256 this.on('activate', function(gp) {
37257 if (!gp.grid.rendered) {
37258 gp.grid.render(this.wrapper);
37259 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37264 this.grid.render(this.wrapper);
37265 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37268 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37269 // ??? needed ??? config.el = this.wrapper;
37274 // xtype created footer. - not sure if will work as we normally have to render first..
37275 if (this.footer && !this.footer.el && this.footer.xtype) {
37277 var ctr = this.grid.getView().getFooterPanel(true);
37278 this.footer.dataSource = this.grid.dataSource;
37279 this.footer = Roo.factory(this.footer, Roo);
37280 this.footer.render(ctr);
37290 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37291 getId : function(){
37292 return this.grid.id;
37296 * Returns the grid for this panel
37297 * @return {Roo.bootstrap.Table}
37299 getGrid : function(){
37303 setSize : function(width, height){
37304 if(!this.ignoreResize(width, height)){
37305 var grid = this.grid;
37306 var size = this.adjustForComponents(width, height);
37307 var gridel = grid.getGridEl();
37308 gridel.setSize(size.width, size.height);
37310 var thd = grid.getGridEl().select('thead',true).first();
37311 var tbd = grid.getGridEl().select('tbody', true).first();
37313 tbd.setSize(width, height - thd.getHeight());
37322 beforeSlide : function(){
37323 this.grid.getView().scroller.clip();
37326 afterSlide : function(){
37327 this.grid.getView().scroller.unclip();
37330 destroy : function(){
37331 this.grid.destroy();
37333 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37338 * @class Roo.bootstrap.panel.Nest
37339 * @extends Roo.bootstrap.panel.Content
37341 * Create a new Panel, that can contain a layout.Border.
37344 * @param {Roo.BorderLayout} layout The layout for this panel
37345 * @param {String/Object} config A string to set only the title or a config object
37347 Roo.bootstrap.panel.Nest = function(config)
37349 // construct with only one argument..
37350 /* FIXME - implement nicer consturctors
37351 if (layout.layout) {
37353 layout = config.layout;
37354 delete config.layout;
37356 if (layout.xtype && !layout.getEl) {
37357 // then layout needs constructing..
37358 layout = Roo.factory(layout, Roo);
37362 config.el = config.layout.getEl();
37364 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37366 config.layout.monitorWindowResize = false; // turn off autosizing
37367 this.layout = config.layout;
37368 this.layout.getEl().addClass("roo-layout-nested-layout");
37375 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37377 setSize : function(width, height){
37378 if(!this.ignoreResize(width, height)){
37379 var size = this.adjustForComponents(width, height);
37380 var el = this.layout.getEl();
37381 if (size.height < 1) {
37382 el.setWidth(size.width);
37384 el.setSize(size.width, size.height);
37386 var touch = el.dom.offsetWidth;
37387 this.layout.layout();
37388 // ie requires a double layout on the first pass
37389 if(Roo.isIE && !this.initialized){
37390 this.initialized = true;
37391 this.layout.layout();
37396 // activate all subpanels if not currently active..
37398 setActiveState : function(active){
37399 this.active = active;
37400 this.setActiveClass(active);
37403 this.fireEvent("deactivate", this);
37407 this.fireEvent("activate", this);
37408 // not sure if this should happen before or after..
37409 if (!this.layout) {
37410 return; // should not happen..
37413 for (var r in this.layout.regions) {
37414 reg = this.layout.getRegion(r);
37415 if (reg.getActivePanel()) {
37416 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37417 reg.setActivePanel(reg.getActivePanel());
37420 if (!reg.panels.length) {
37423 reg.showPanel(reg.getPanel(0));
37432 * Returns the nested BorderLayout for this panel
37433 * @return {Roo.BorderLayout}
37435 getLayout : function(){
37436 return this.layout;
37440 * Adds a xtype elements to the layout of the nested panel
37444 xtype : 'ContentPanel',
37451 xtype : 'NestedLayoutPanel',
37457 items : [ ... list of content panels or nested layout panels.. ]
37461 * @param {Object} cfg Xtype definition of item to add.
37463 addxtype : function(cfg) {
37464 return this.layout.addxtype(cfg);
37469 * Ext JS Library 1.1.1
37470 * Copyright(c) 2006-2007, Ext JS, LLC.
37472 * Originally Released Under LGPL - original licence link has changed is not relivant.
37475 * <script type="text/javascript">
37478 * @class Roo.TabPanel
37479 * @extends Roo.util.Observable
37480 * A lightweight tab container.
37484 // basic tabs 1, built from existing content
37485 var tabs = new Roo.TabPanel("tabs1");
37486 tabs.addTab("script", "View Script");
37487 tabs.addTab("markup", "View Markup");
37488 tabs.activate("script");
37490 // more advanced tabs, built from javascript
37491 var jtabs = new Roo.TabPanel("jtabs");
37492 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37494 // set up the UpdateManager
37495 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37496 var updater = tab2.getUpdateManager();
37497 updater.setDefaultUrl("ajax1.htm");
37498 tab2.on('activate', updater.refresh, updater, true);
37500 // Use setUrl for Ajax loading
37501 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37502 tab3.setUrl("ajax2.htm", null, true);
37505 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37508 jtabs.activate("jtabs-1");
37511 * Create a new TabPanel.
37512 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37513 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37515 Roo.bootstrap.panel.Tabs = function(config){
37517 * The container element for this TabPanel.
37518 * @type Roo.Element
37520 this.el = Roo.get(config.el);
37523 if(typeof config == "boolean"){
37524 this.tabPosition = config ? "bottom" : "top";
37526 Roo.apply(this, config);
37530 if(this.tabPosition == "bottom"){
37531 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37532 this.el.addClass("roo-tabs-bottom");
37534 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37535 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37536 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37538 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37540 if(this.tabPosition != "bottom"){
37541 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37542 * @type Roo.Element
37544 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37545 this.el.addClass("roo-tabs-top");
37549 this.bodyEl.setStyle("position", "relative");
37551 this.active = null;
37552 this.activateDelegate = this.activate.createDelegate(this);
37557 * Fires when the active tab changes
37558 * @param {Roo.TabPanel} this
37559 * @param {Roo.TabPanelItem} activePanel The new active tab
37563 * @event beforetabchange
37564 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37565 * @param {Roo.TabPanel} this
37566 * @param {Object} e Set cancel to true on this object to cancel the tab change
37567 * @param {Roo.TabPanelItem} tab The tab being changed to
37569 "beforetabchange" : true
37572 Roo.EventManager.onWindowResize(this.onResize, this);
37573 this.cpad = this.el.getPadding("lr");
37574 this.hiddenCount = 0;
37577 // toolbar on the tabbar support...
37578 if (this.toolbar) {
37579 alert("no toolbar support yet");
37580 this.toolbar = false;
37582 var tcfg = this.toolbar;
37583 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37584 this.toolbar = new Roo.Toolbar(tcfg);
37585 if (Roo.isSafari) {
37586 var tbl = tcfg.container.child('table', true);
37587 tbl.setAttribute('width', '100%');
37595 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37598 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37600 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37602 tabPosition : "top",
37604 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37606 currentTabWidth : 0,
37608 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37612 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37616 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37618 preferredTabWidth : 175,
37620 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37622 resizeTabs : false,
37624 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37626 monitorResize : true,
37628 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37633 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37634 * @param {String} id The id of the div to use <b>or create</b>
37635 * @param {String} text The text for the tab
37636 * @param {String} content (optional) Content to put in the TabPanelItem body
37637 * @param {Boolean} closable (optional) True to create a close icon on the tab
37638 * @return {Roo.TabPanelItem} The created TabPanelItem
37640 addTab : function(id, text, content, closable, tpl)
37642 var item = new Roo.bootstrap.panel.TabItem({
37646 closable : closable,
37649 this.addTabItem(item);
37651 item.setContent(content);
37657 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37658 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37659 * @return {Roo.TabPanelItem}
37661 getTab : function(id){
37662 return this.items[id];
37666 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37667 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37669 hideTab : function(id){
37670 var t = this.items[id];
37673 this.hiddenCount++;
37674 this.autoSizeTabs();
37679 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37680 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37682 unhideTab : function(id){
37683 var t = this.items[id];
37685 t.setHidden(false);
37686 this.hiddenCount--;
37687 this.autoSizeTabs();
37692 * Adds an existing {@link Roo.TabPanelItem}.
37693 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37695 addTabItem : function(item){
37696 this.items[item.id] = item;
37697 this.items.push(item);
37698 // if(this.resizeTabs){
37699 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37700 // this.autoSizeTabs();
37702 // item.autoSize();
37707 * Removes a {@link Roo.TabPanelItem}.
37708 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37710 removeTab : function(id){
37711 var items = this.items;
37712 var tab = items[id];
37713 if(!tab) { return; }
37714 var index = items.indexOf(tab);
37715 if(this.active == tab && items.length > 1){
37716 var newTab = this.getNextAvailable(index);
37721 this.stripEl.dom.removeChild(tab.pnode.dom);
37722 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37723 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37725 items.splice(index, 1);
37726 delete this.items[tab.id];
37727 tab.fireEvent("close", tab);
37728 tab.purgeListeners();
37729 this.autoSizeTabs();
37732 getNextAvailable : function(start){
37733 var items = this.items;
37735 // look for a next tab that will slide over to
37736 // replace the one being removed
37737 while(index < items.length){
37738 var item = items[++index];
37739 if(item && !item.isHidden()){
37743 // if one isn't found select the previous tab (on the left)
37746 var item = items[--index];
37747 if(item && !item.isHidden()){
37755 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37756 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37758 disableTab : function(id){
37759 var tab = this.items[id];
37760 if(tab && this.active != tab){
37766 * Enables a {@link Roo.TabPanelItem} that is disabled.
37767 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37769 enableTab : function(id){
37770 var tab = this.items[id];
37775 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37776 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37777 * @return {Roo.TabPanelItem} The TabPanelItem.
37779 activate : function(id){
37780 var tab = this.items[id];
37784 if(tab == this.active || tab.disabled){
37788 this.fireEvent("beforetabchange", this, e, tab);
37789 if(e.cancel !== true && !tab.disabled){
37791 this.active.hide();
37793 this.active = this.items[id];
37794 this.active.show();
37795 this.fireEvent("tabchange", this, this.active);
37801 * Gets the active {@link Roo.TabPanelItem}.
37802 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37804 getActiveTab : function(){
37805 return this.active;
37809 * Updates the tab body element to fit the height of the container element
37810 * for overflow scrolling
37811 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37813 syncHeight : function(targetHeight){
37814 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37815 var bm = this.bodyEl.getMargins();
37816 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37817 this.bodyEl.setHeight(newHeight);
37821 onResize : function(){
37822 if(this.monitorResize){
37823 this.autoSizeTabs();
37828 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37830 beginUpdate : function(){
37831 this.updating = true;
37835 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37837 endUpdate : function(){
37838 this.updating = false;
37839 this.autoSizeTabs();
37843 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37845 autoSizeTabs : function(){
37846 var count = this.items.length;
37847 var vcount = count - this.hiddenCount;
37848 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37851 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37852 var availWidth = Math.floor(w / vcount);
37853 var b = this.stripBody;
37854 if(b.getWidth() > w){
37855 var tabs = this.items;
37856 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37857 if(availWidth < this.minTabWidth){
37858 /*if(!this.sleft){ // incomplete scrolling code
37859 this.createScrollButtons();
37862 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37865 if(this.currentTabWidth < this.preferredTabWidth){
37866 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37872 * Returns the number of tabs in this TabPanel.
37875 getCount : function(){
37876 return this.items.length;
37880 * Resizes all the tabs to the passed width
37881 * @param {Number} The new width
37883 setTabWidth : function(width){
37884 this.currentTabWidth = width;
37885 for(var i = 0, len = this.items.length; i < len; i++) {
37886 if(!this.items[i].isHidden()) {
37887 this.items[i].setWidth(width);
37893 * Destroys this TabPanel
37894 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37896 destroy : function(removeEl){
37897 Roo.EventManager.removeResizeListener(this.onResize, this);
37898 for(var i = 0, len = this.items.length; i < len; i++){
37899 this.items[i].purgeListeners();
37901 if(removeEl === true){
37902 this.el.update("");
37907 createStrip : function(container)
37909 var strip = document.createElement("nav");
37910 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37911 container.appendChild(strip);
37915 createStripList : function(strip)
37917 // div wrapper for retard IE
37918 // returns the "tr" element.
37919 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37920 //'<div class="x-tabs-strip-wrap">'+
37921 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37922 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37923 return strip.firstChild; //.firstChild.firstChild.firstChild;
37925 createBody : function(container)
37927 var body = document.createElement("div");
37928 Roo.id(body, "tab-body");
37929 //Roo.fly(body).addClass("x-tabs-body");
37930 Roo.fly(body).addClass("tab-content");
37931 container.appendChild(body);
37934 createItemBody :function(bodyEl, id){
37935 var body = Roo.getDom(id);
37937 body = document.createElement("div");
37940 //Roo.fly(body).addClass("x-tabs-item-body");
37941 Roo.fly(body).addClass("tab-pane");
37942 bodyEl.insertBefore(body, bodyEl.firstChild);
37946 createStripElements : function(stripEl, text, closable, tpl)
37948 var td = document.createElement("li"); // was td..
37951 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37954 stripEl.appendChild(td);
37956 td.className = "x-tabs-closable";
37957 if(!this.closeTpl){
37958 this.closeTpl = new Roo.Template(
37959 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37960 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37961 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37964 var el = this.closeTpl.overwrite(td, {"text": text});
37965 var close = el.getElementsByTagName("div")[0];
37966 var inner = el.getElementsByTagName("em")[0];
37967 return {"el": el, "close": close, "inner": inner};
37970 // not sure what this is..
37971 // if(!this.tabTpl){
37972 //this.tabTpl = new Roo.Template(
37973 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37974 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37976 // this.tabTpl = new Roo.Template(
37977 // '<a href="#">' +
37978 // '<span unselectable="on"' +
37979 // (this.disableTooltips ? '' : ' title="{text}"') +
37980 // ' >{text}</span></a>'
37986 var template = tpl || this.tabTpl || false;
37990 template = new Roo.Template(
37992 '<span unselectable="on"' +
37993 (this.disableTooltips ? '' : ' title="{text}"') +
37994 ' >{text}</span></a>'
37998 switch (typeof(template)) {
38002 template = new Roo.Template(template);
38008 var el = template.overwrite(td, {"text": text});
38010 var inner = el.getElementsByTagName("span")[0];
38012 return {"el": el, "inner": inner};
38020 * @class Roo.TabPanelItem
38021 * @extends Roo.util.Observable
38022 * Represents an individual item (tab plus body) in a TabPanel.
38023 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38024 * @param {String} id The id of this TabPanelItem
38025 * @param {String} text The text for the tab of this TabPanelItem
38026 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38028 Roo.bootstrap.panel.TabItem = function(config){
38030 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38031 * @type Roo.TabPanel
38033 this.tabPanel = config.panel;
38035 * The id for this TabPanelItem
38038 this.id = config.id;
38040 this.disabled = false;
38042 this.text = config.text;
38044 this.loaded = false;
38045 this.closable = config.closable;
38048 * The body element for this TabPanelItem.
38049 * @type Roo.Element
38051 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38052 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38053 this.bodyEl.setStyle("display", "block");
38054 this.bodyEl.setStyle("zoom", "1");
38055 //this.hideAction();
38057 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38059 this.el = Roo.get(els.el);
38060 this.inner = Roo.get(els.inner, true);
38061 this.textEl = Roo.get(this.el.dom.firstChild, true);
38062 this.pnode = Roo.get(els.el.parentNode, true);
38063 // this.el.on("mousedown", this.onTabMouseDown, this);
38064 this.el.on("click", this.onTabClick, this);
38066 if(config.closable){
38067 var c = Roo.get(els.close, true);
38068 c.dom.title = this.closeText;
38069 c.addClassOnOver("close-over");
38070 c.on("click", this.closeClick, this);
38076 * Fires when this tab becomes the active tab.
38077 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38078 * @param {Roo.TabPanelItem} this
38082 * @event beforeclose
38083 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38084 * @param {Roo.TabPanelItem} this
38085 * @param {Object} e Set cancel to true on this object to cancel the close.
38087 "beforeclose": true,
38090 * Fires when this tab is closed.
38091 * @param {Roo.TabPanelItem} this
38095 * @event deactivate
38096 * Fires when this tab is no longer the active tab.
38097 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38098 * @param {Roo.TabPanelItem} this
38100 "deactivate" : true
38102 this.hidden = false;
38104 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38107 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38109 purgeListeners : function(){
38110 Roo.util.Observable.prototype.purgeListeners.call(this);
38111 this.el.removeAllListeners();
38114 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38117 this.pnode.addClass("active");
38120 this.tabPanel.stripWrap.repaint();
38122 this.fireEvent("activate", this.tabPanel, this);
38126 * Returns true if this tab is the active tab.
38127 * @return {Boolean}
38129 isActive : function(){
38130 return this.tabPanel.getActiveTab() == this;
38134 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38137 this.pnode.removeClass("active");
38139 this.fireEvent("deactivate", this.tabPanel, this);
38142 hideAction : function(){
38143 this.bodyEl.hide();
38144 this.bodyEl.setStyle("position", "absolute");
38145 this.bodyEl.setLeft("-20000px");
38146 this.bodyEl.setTop("-20000px");
38149 showAction : function(){
38150 this.bodyEl.setStyle("position", "relative");
38151 this.bodyEl.setTop("");
38152 this.bodyEl.setLeft("");
38153 this.bodyEl.show();
38157 * Set the tooltip for the tab.
38158 * @param {String} tooltip The tab's tooltip
38160 setTooltip : function(text){
38161 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38162 this.textEl.dom.qtip = text;
38163 this.textEl.dom.removeAttribute('title');
38165 this.textEl.dom.title = text;
38169 onTabClick : function(e){
38170 e.preventDefault();
38171 this.tabPanel.activate(this.id);
38174 onTabMouseDown : function(e){
38175 e.preventDefault();
38176 this.tabPanel.activate(this.id);
38179 getWidth : function(){
38180 return this.inner.getWidth();
38183 setWidth : function(width){
38184 var iwidth = width - this.pnode.getPadding("lr");
38185 this.inner.setWidth(iwidth);
38186 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38187 this.pnode.setWidth(width);
38191 * Show or hide the tab
38192 * @param {Boolean} hidden True to hide or false to show.
38194 setHidden : function(hidden){
38195 this.hidden = hidden;
38196 this.pnode.setStyle("display", hidden ? "none" : "");
38200 * Returns true if this tab is "hidden"
38201 * @return {Boolean}
38203 isHidden : function(){
38204 return this.hidden;
38208 * Returns the text for this tab
38211 getText : function(){
38215 autoSize : function(){
38216 //this.el.beginMeasure();
38217 this.textEl.setWidth(1);
38219 * #2804 [new] Tabs in Roojs
38220 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38222 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38223 //this.el.endMeasure();
38227 * Sets the text for the tab (Note: this also sets the tooltip text)
38228 * @param {String} text The tab's text and tooltip
38230 setText : function(text){
38232 this.textEl.update(text);
38233 this.setTooltip(text);
38234 //if(!this.tabPanel.resizeTabs){
38235 // this.autoSize();
38239 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38241 activate : function(){
38242 this.tabPanel.activate(this.id);
38246 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38248 disable : function(){
38249 if(this.tabPanel.active != this){
38250 this.disabled = true;
38251 this.pnode.addClass("disabled");
38256 * Enables this TabPanelItem if it was previously disabled.
38258 enable : function(){
38259 this.disabled = false;
38260 this.pnode.removeClass("disabled");
38264 * Sets the content for this TabPanelItem.
38265 * @param {String} content The content
38266 * @param {Boolean} loadScripts true to look for and load scripts
38268 setContent : function(content, loadScripts){
38269 this.bodyEl.update(content, loadScripts);
38273 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38274 * @return {Roo.UpdateManager} The UpdateManager
38276 getUpdateManager : function(){
38277 return this.bodyEl.getUpdateManager();
38281 * Set a URL to be used to load the content for this TabPanelItem.
38282 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38283 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
38284 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
38285 * @return {Roo.UpdateManager} The UpdateManager
38287 setUrl : function(url, params, loadOnce){
38288 if(this.refreshDelegate){
38289 this.un('activate', this.refreshDelegate);
38291 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38292 this.on("activate", this.refreshDelegate);
38293 return this.bodyEl.getUpdateManager();
38297 _handleRefresh : function(url, params, loadOnce){
38298 if(!loadOnce || !this.loaded){
38299 var updater = this.bodyEl.getUpdateManager();
38300 updater.update(url, params, this._setLoaded.createDelegate(this));
38305 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38306 * Will fail silently if the setUrl method has not been called.
38307 * This does not activate the panel, just updates its content.
38309 refresh : function(){
38310 if(this.refreshDelegate){
38311 this.loaded = false;
38312 this.refreshDelegate();
38317 _setLoaded : function(){
38318 this.loaded = true;
38322 closeClick : function(e){
38325 this.fireEvent("beforeclose", this, o);
38326 if(o.cancel !== true){
38327 this.tabPanel.removeTab(this.id);
38331 * The text displayed in the tooltip for the close icon.
38334 closeText : "Close this tab"
38337 * This script refer to:
38338 * Title: International Telephone Input
38339 * Author: Jack O'Connor
38340 * Code version: v12.1.12
38341 * Availability: https://github.com/jackocnr/intl-tel-input.git
38344 Roo.bootstrap.PhoneInputData = function() {
38347 "Afghanistan (افغانستان)",
38352 "Albania (Shqipëri)",
38357 "Algeria (الجزائر)",
38382 "Antigua and Barbuda",
38392 "Armenia (Հայաստան)",
38408 "Austria (Österreich)",
38413 "Azerbaijan (Azərbaycan)",
38423 "Bahrain (البحرين)",
38428 "Bangladesh (বাংলাদেশ)",
38438 "Belarus (Беларусь)",
38443 "Belgium (België)",
38473 "Bosnia and Herzegovina (Босна и Херцеговина)",
38488 "British Indian Ocean Territory",
38493 "British Virgin Islands",
38503 "Bulgaria (България)",
38513 "Burundi (Uburundi)",
38518 "Cambodia (កម្ពុជា)",
38523 "Cameroon (Cameroun)",
38532 ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]
38535 "Cape Verde (Kabu Verdi)",
38540 "Caribbean Netherlands",
38551 "Central African Republic (République centrafricaine)",
38571 "Christmas Island",
38577 "Cocos (Keeling) Islands",
38588 "Comoros (جزر القمر)",
38593 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38598 "Congo (Republic) (Congo-Brazzaville)",
38618 "Croatia (Hrvatska)",
38639 "Czech Republic (Česká republika)",
38644 "Denmark (Danmark)",
38659 "Dominican Republic (República Dominicana)",
38663 ["809", "829", "849"]
38681 "Equatorial Guinea (Guinea Ecuatorial)",
38701 "Falkland Islands (Islas Malvinas)",
38706 "Faroe Islands (Føroyar)",
38727 "French Guiana (Guyane française)",
38732 "French Polynesia (Polynésie française)",
38747 "Georgia (საქართველო)",
38752 "Germany (Deutschland)",
38772 "Greenland (Kalaallit Nunaat)",
38809 "Guinea-Bissau (Guiné Bissau)",
38834 "Hungary (Magyarország)",
38839 "Iceland (Ísland)",
38859 "Iraq (العراق)",
38875 "Israel (ישראל)",
38902 "Jordan (الأردن)",
38907 "Kazakhstan (Казахстан)",
38928 "Kuwait (الكويت)",
38933 "Kyrgyzstan (Кыргызстан)",
38943 "Latvia (Latvija)",
38948 "Lebanon (لبنان)",
38963 "Libya (ليبيا)",
38973 "Lithuania (Lietuva)",
38988 "Macedonia (FYROM) (Македонија)",
38993 "Madagascar (Madagasikara)",
39023 "Marshall Islands",
39033 "Mauritania (موريتانيا)",
39038 "Mauritius (Moris)",
39059 "Moldova (Republica Moldova)",
39069 "Mongolia (Монгол)",
39074 "Montenegro (Crna Gora)",
39084 "Morocco (المغرب)",
39090 "Mozambique (Moçambique)",
39095 "Myanmar (Burma) (မြန်မာ)",
39100 "Namibia (Namibië)",
39115 "Netherlands (Nederland)",
39120 "New Caledonia (Nouvelle-Calédonie)",
39155 "North Korea (조선 민주주의 인민 공화국)",
39160 "Northern Mariana Islands",
39176 "Pakistan (پاکستان)",
39186 "Palestine (فلسطين)",
39196 "Papua New Guinea",
39238 "Réunion (La Réunion)",
39244 "Romania (România)",
39260 "Saint Barthélemy",
39271 "Saint Kitts and Nevis",
39281 "Saint Martin (Saint-Martin (partie française))",
39287 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39292 "Saint Vincent and the Grenadines",
39307 "São Tomé and Príncipe (São Tomé e Príncipe)",
39312 "Saudi Arabia (المملكة العربية السعودية)",
39317 "Senegal (Sénégal)",
39347 "Slovakia (Slovensko)",
39352 "Slovenia (Slovenija)",
39362 "Somalia (Soomaaliya)",
39372 "South Korea (대한민국)",
39377 "South Sudan (جنوب السودان)",
39387 "Sri Lanka (ශ්රී ලංකාව)",
39392 "Sudan (السودان)",
39402 "Svalbard and Jan Mayen",
39413 "Sweden (Sverige)",
39418 "Switzerland (Schweiz)",
39423 "Syria (سوريا)",
39468 "Trinidad and Tobago",
39473 "Tunisia (تونس)",
39478 "Turkey (Türkiye)",
39488 "Turks and Caicos Islands",
39498 "U.S. Virgin Islands",
39508 "Ukraine (Україна)",
39513 "United Arab Emirates (الإمارات العربية المتحدة)",
39535 "Uzbekistan (Oʻzbekiston)",
39545 "Vatican City (Città del Vaticano)",
39556 "Vietnam (Việt Nam)",
39561 "Wallis and Futuna (Wallis-et-Futuna)",
39566 "Western Sahara (الصحراء الغربية)",
39572 "Yemen (اليمن)",
39596 * This script refer to:
39597 * Title: International Telephone Input
39598 * Author: Jack O'Connor
39599 * Code version: v12.1.12
39600 * Availability: https://github.com/jackocnr/intl-tel-input.git
39604 * @class Roo.bootstrap.PhoneInput
39605 * @extends Roo.bootstrap.TriggerField
39606 * An input with International dial-code selection
39608 * @cfg {String} defaultDialCode default '+852'
39609 * @cfg {Array} preferedCountries default []
39612 * Create a new PhoneInput.
39613 * @param {Object} config Configuration options
39616 Roo.bootstrap.PhoneInput = function(config) {
39617 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39620 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39622 listWidth: undefined,
39624 selectedClass: 'active',
39626 invalidClass : "has-warning",
39628 validClass: 'has-success',
39630 allowed: '0123456789',
39633 * @cfg {String} defaultDialCode The default dial code when initializing the input
39635 defaultDialCode: '+852',
39638 * @cfg {Array} preferedCountries A list of iso2 in array (e.g. ['hk','us']). Those related countries will show at the top of the input's choices
39640 preferedCountries: false,
39642 getAutoCreate : function()
39644 var data = Roo.bootstrap.PhoneInputData();
39645 var align = this.labelAlign || this.parentLabelAlign();
39648 this.allCountries = [];
39649 this.dialCodeMapping = [];
39651 for (var i = 0; i < data.length; i++) {
39653 this.allCountries[i] = {
39657 priority: c[3] || 0,
39658 areaCodes: c[4] || null
39660 this.dialCodeMapping[c[2]] = {
39663 priority: c[3] || 0,
39664 areaCodes: c[4] || null
39676 cls : 'form-control tel-input',
39677 autocomplete: 'new-password'
39680 var hiddenInput = {
39683 cls: 'hidden-tel-input'
39687 hiddenInput.name = this.name;
39690 if (this.disabled) {
39691 input.disabled = true;
39694 var flag_container = {
39711 cls: this.hasFeedback ? 'has-feedback' : '',
39717 cls: 'dial-code-holder',
39724 cls: 'roo-select2-container input-group',
39731 if (this.fieldLabel.length) {
39734 tooltip: 'This field is required'
39740 cls: 'control-label',
39746 html: this.fieldLabel
39749 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39755 if(this.indicatorpos == 'right') {
39756 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39763 if(align == 'left') {
39771 if(this.labelWidth > 12){
39772 label.style = "width: " + this.labelWidth + 'px';
39774 if(this.labelWidth < 13 && this.labelmd == 0){
39775 this.labelmd = this.labelWidth;
39777 if(this.labellg > 0){
39778 label.cls += ' col-lg-' + this.labellg;
39779 input.cls += ' col-lg-' + (12 - this.labellg);
39781 if(this.labelmd > 0){
39782 label.cls += ' col-md-' + this.labelmd;
39783 container.cls += ' col-md-' + (12 - this.labelmd);
39785 if(this.labelsm > 0){
39786 label.cls += ' col-sm-' + this.labelsm;
39787 container.cls += ' col-sm-' + (12 - this.labelsm);
39789 if(this.labelxs > 0){
39790 label.cls += ' col-xs-' + this.labelxs;
39791 container.cls += ' col-xs-' + (12 - this.labelxs);
39801 var settings = this;
39803 ['xs','sm','md','lg'].map(function(size){
39804 if (settings[size]) {
39805 cfg.cls += ' col-' + size + '-' + settings[size];
39809 this.store = new Roo.data.Store({
39810 proxy : new Roo.data.MemoryProxy({}),
39811 reader : new Roo.data.JsonReader({
39822 'name' : 'dialCode',
39826 'name' : 'priority',
39830 'name' : 'areaCodes',
39837 if(!this.preferedCountries) {
39838 this.preferedCountries = [
39845 var p = this.preferedCountries.reverse();
39848 for (var i = 0; i < p.length; i++) {
39849 for (var j = 0; j < this.allCountries.length; j++) {
39850 if(this.allCountries[j].iso2 == p[i]) {
39851 var t = this.allCountries[j];
39852 this.allCountries.splice(j,1);
39853 this.allCountries.unshift(t);
39859 this.store.proxy.data = {
39861 data: this.allCountries
39867 initEvents : function()
39870 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39872 this.indicator = this.indicatorEl();
39873 this.flag = this.flagEl();
39874 this.dialCodeHolder = this.dialCodeHolderEl();
39876 this.trigger = this.el.select('div.flag-box',true).first();
39877 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39882 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39883 _this.list.setWidth(lw);
39886 this.list.on('mouseover', this.onViewOver, this);
39887 this.list.on('mousemove', this.onViewMove, this);
39888 this.inputEl().on("keyup", this.onKeyUp, this);
39890 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39892 this.view = new Roo.View(this.list, this.tpl, {
39893 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39896 this.view.on('click', this.onViewClick, this);
39897 this.setValue(this.defaultDialCode);
39900 onTriggerClick : function(e)
39902 Roo.log('trigger click');
39907 if(this.isExpanded()){
39909 this.hasFocus = false;
39911 this.store.load({});
39912 this.hasFocus = true;
39917 isExpanded : function()
39919 return this.list.isVisible();
39922 collapse : function()
39924 if(!this.isExpanded()){
39928 Roo.get(document).un('mousedown', this.collapseIf, this);
39929 Roo.get(document).un('mousewheel', this.collapseIf, this);
39930 this.fireEvent('collapse', this);
39934 expand : function()
39938 if(this.isExpanded() || !this.hasFocus){
39942 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39943 this.list.setWidth(lw);
39946 this.restrictHeight();
39948 Roo.get(document).on('mousedown', this.collapseIf, this);
39949 Roo.get(document).on('mousewheel', this.collapseIf, this);
39951 this.fireEvent('expand', this);
39954 restrictHeight : function()
39956 this.list.alignTo(this.inputEl(), this.listAlign);
39957 this.list.alignTo(this.inputEl(), this.listAlign);
39960 onViewOver : function(e, t)
39962 if(this.inKeyMode){
39965 var item = this.view.findItemFromChild(t);
39968 var index = this.view.indexOf(item);
39969 this.select(index, false);
39974 onViewClick : function(view, doFocus, el, e)
39976 var index = this.view.getSelectedIndexes()[0];
39978 var r = this.store.getAt(index);
39981 this.onSelect(r, index);
39983 if(doFocus !== false && !this.blockFocus){
39984 this.inputEl().focus();
39988 onViewMove : function(e, t)
39990 this.inKeyMode = false;
39993 select : function(index, scrollIntoView)
39995 this.selectedIndex = index;
39996 this.view.select(index);
39997 if(scrollIntoView !== false){
39998 var el = this.view.getNode(index);
40000 this.list.scrollChildIntoView(el, false);
40005 createList : function()
40007 this.list = Roo.get(document.body).createChild({
40009 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40010 style: 'display:none'
40012 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
40015 collapseIf : function(e)
40017 var in_combo = e.within(this.el);
40018 var in_list = e.within(this.list);
40019 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40021 if (in_combo || in_list || is_list) {
40027 onSelect : function(record, index)
40029 if(this.fireEvent('beforeselect', this, record, index) !== false){
40031 this.setFlagClass(record.data.iso2);
40032 this.setDialCode(record.data.dialCode);
40033 this.hasFocus = false;
40035 this.fireEvent('select', this, record, index);
40039 flagEl : function()
40041 var flag = this.el.select('div.flag',true).first();
40048 dialCodeHolderEl : function()
40050 var d = this.el.select('input.dial-code-holder',true).first();
40057 setDialCode : function(v)
40059 this.dialCodeHolder.dom.value = '+'+v;
40062 setFlagClass : function(n)
40064 this.flag.dom.className = 'flag '+n;
40067 getValue : function()
40069 var v = this.inputEl().getValue();
40070 if(this.dialCodeHolder) {
40071 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40076 setValue : function(v)
40078 var d = this.getDialCode(v);
40080 //invalid dial code
40081 if(v.length == 0 || !d || d.length == 0) {
40083 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40084 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40090 this.setFlagClass(this.dialCodeMapping[d].iso2);
40091 this.setDialCode(d);
40092 this.inputEl().dom.value = v.replace('+'+d,'');
40093 this.hiddenEl().dom.value = this.getValue();
40098 getDialCode : function(v = '')
40100 if (v.length == 0) {
40101 return this.dialCodeHolder.dom.value;
40105 if (v.charAt(0) != "+") {
40108 var numericChars = "";
40109 for (var i = 1; i < v.length; i++) {
40110 var c = v.charAt(i);
40113 if (this.dialCodeMapping[numericChars]) {
40114 dialCode = v.substr(1, i);
40116 if (numericChars.length == 4) {
40126 this.setValue(this.defaultDialCode);
40130 hiddenEl : function()
40132 return this.el.select('input.hidden-tel-input',true).first();
40135 onKeyUp : function(e){
40137 var k = e.getKey();
40138 var c = e.getCharCode();
40141 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40142 this.allowed.indexOf(String.fromCharCode(c)) === -1
40147 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40150 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40154 this.setValue(this.getValue());
40159 * @class Roo.bootstrap.MoneyField
40160 * @extends Roo.bootstrap.ComboBox
40161 * Bootstrap MoneyField class
40164 * Create a new MoneyField.
40165 * @param {Object} config Configuration options
40168 Roo.bootstrap.MoneyField = function(config) {
40170 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40174 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40177 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40179 allowDecimals : true,
40181 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40183 decimalSeparator : ".",
40185 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40187 decimalPrecision : 0,
40189 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40191 allowNegative : true,
40193 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40195 minValue : Number.NEGATIVE_INFINITY,
40197 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40199 maxValue : Number.MAX_VALUE,
40201 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40203 minText : "The minimum value for this field is {0}",
40205 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40207 maxText : "The maximum value for this field is {0}",
40209 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40210 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40212 nanText : "{0} is not a valid number",
40214 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40218 * @cfg {String} defaults currency of the MoneyField
40219 * value should be in lkey
40221 defaultCurrency : false,
40223 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40225 thousandsDelimiter : false,
40235 getAutoCreate : function()
40237 var align = this.labelAlign || this.parentLabelAlign();
40249 cls : 'form-control roo-money-amount-input',
40250 autocomplete: 'new-password'
40253 var hiddenInput = {
40257 cls: 'hidden-number-input'
40261 hiddenInput.name = this.name;
40264 if (this.disabled) {
40265 input.disabled = true;
40268 var clg = 12 - this.inputlg;
40269 var cmd = 12 - this.inputmd;
40270 var csm = 12 - this.inputsm;
40271 var cxs = 12 - this.inputxs;
40275 cls : 'row roo-money-field',
40279 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40283 cls: 'roo-select2-container input-group',
40287 cls : 'form-control roo-money-currency-input',
40288 autocomplete: 'new-password',
40290 name : this.currencyName
40294 cls : 'input-group-addon',
40308 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40312 cls: this.hasFeedback ? 'has-feedback' : '',
40323 if (this.fieldLabel.length) {
40326 tooltip: 'This field is required'
40332 cls: 'control-label',
40338 html: this.fieldLabel
40341 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40347 if(this.indicatorpos == 'right') {
40348 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40355 if(align == 'left') {
40363 if(this.labelWidth > 12){
40364 label.style = "width: " + this.labelWidth + 'px';
40366 if(this.labelWidth < 13 && this.labelmd == 0){
40367 this.labelmd = this.labelWidth;
40369 if(this.labellg > 0){
40370 label.cls += ' col-lg-' + this.labellg;
40371 input.cls += ' col-lg-' + (12 - this.labellg);
40373 if(this.labelmd > 0){
40374 label.cls += ' col-md-' + this.labelmd;
40375 container.cls += ' col-md-' + (12 - this.labelmd);
40377 if(this.labelsm > 0){
40378 label.cls += ' col-sm-' + this.labelsm;
40379 container.cls += ' col-sm-' + (12 - this.labelsm);
40381 if(this.labelxs > 0){
40382 label.cls += ' col-xs-' + this.labelxs;
40383 container.cls += ' col-xs-' + (12 - this.labelxs);
40394 var settings = this;
40396 ['xs','sm','md','lg'].map(function(size){
40397 if (settings[size]) {
40398 cfg.cls += ' col-' + size + '-' + settings[size];
40405 initEvents : function()
40407 this.indicator = this.indicatorEl();
40409 this.initCurrencyEvent();
40411 this.initNumberEvent();
40414 initCurrencyEvent : function()
40417 throw "can not find store for combo";
40420 this.store = Roo.factory(this.store, Roo.data);
40421 this.store.parent = this;
40425 this.triggerEl = this.el.select('.input-group-addon', true).first();
40427 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40432 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40433 _this.list.setWidth(lw);
40436 this.list.on('mouseover', this.onViewOver, this);
40437 this.list.on('mousemove', this.onViewMove, this);
40438 this.list.on('scroll', this.onViewScroll, this);
40441 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40444 this.view = new Roo.View(this.list, this.tpl, {
40445 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40448 this.view.on('click', this.onViewClick, this);
40450 this.store.on('beforeload', this.onBeforeLoad, this);
40451 this.store.on('load', this.onLoad, this);
40452 this.store.on('loadexception', this.onLoadException, this);
40454 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40455 "up" : function(e){
40456 this.inKeyMode = true;
40460 "down" : function(e){
40461 if(!this.isExpanded()){
40462 this.onTriggerClick();
40464 this.inKeyMode = true;
40469 "enter" : function(e){
40472 if(this.fireEvent("specialkey", this, e)){
40473 this.onViewClick(false);
40479 "esc" : function(e){
40483 "tab" : function(e){
40486 if(this.fireEvent("specialkey", this, e)){
40487 this.onViewClick(false);
40495 doRelay : function(foo, bar, hname){
40496 if(hname == 'down' || this.scope.isExpanded()){
40497 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40505 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40509 initNumberEvent : function(e)
40511 this.inputEl().on("keydown" , this.fireKey, this);
40512 this.inputEl().on("focus", this.onFocus, this);
40513 this.inputEl().on("blur", this.onBlur, this);
40515 this.inputEl().relayEvent('keyup', this);
40517 if(this.indicator){
40518 this.indicator.addClass('invisible');
40521 this.originalValue = this.getValue();
40523 if(this.validationEvent == 'keyup'){
40524 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40525 this.inputEl().on('keyup', this.filterValidation, this);
40527 else if(this.validationEvent !== false){
40528 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40531 if(this.selectOnFocus){
40532 this.on("focus", this.preFocus, this);
40535 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40536 this.inputEl().on("keypress", this.filterKeys, this);
40538 this.inputEl().relayEvent('keypress', this);
40541 var allowed = "0123456789";
40543 if(this.allowDecimals){
40544 allowed += this.decimalSeparator;
40547 if(this.allowNegative){
40551 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40553 var keyPress = function(e){
40555 var k = e.getKey();
40557 var c = e.getCharCode();
40560 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40561 allowed.indexOf(String.fromCharCode(c)) === -1
40567 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40571 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40576 this.inputEl().on("keypress", keyPress, this);
40580 onTriggerClick : function(e)
40587 this.loadNext = false;
40589 if(this.isExpanded()){
40594 this.hasFocus = true;
40596 if(this.triggerAction == 'all') {
40597 this.doQuery(this.allQuery, true);
40601 this.doQuery(this.getRawValue());
40604 getCurrency : function()
40606 var v = this.currencyEl().getValue();
40611 restrictHeight : function()
40613 this.list.alignTo(this.currencyEl(), this.listAlign);
40614 this.list.alignTo(this.currencyEl(), this.listAlign);
40617 onViewClick : function(view, doFocus, el, e)
40619 var index = this.view.getSelectedIndexes()[0];
40621 var r = this.store.getAt(index);
40624 this.onSelect(r, index);
40628 onSelect : function(record, index){
40630 if(this.fireEvent('beforeselect', this, record, index) !== false){
40632 this.setFromCurrencyData(index > -1 ? record.data : false);
40636 this.fireEvent('select', this, record, index);
40640 setFromCurrencyData : function(o)
40644 this.lastCurrency = o;
40646 if (this.currencyField) {
40647 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40649 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40652 this.lastSelectionText = currency;
40654 //setting default currency
40655 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40656 this.setCurrency(this.defaultCurrency);
40660 this.setCurrency(currency);
40663 setFromData : function(o)
40667 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40669 this.setFromCurrencyData(c);
40674 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40676 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40679 this.setValue(value);
40683 setCurrency : function(v)
40685 this.currencyValue = v;
40688 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40693 setValue : function(v)
40695 v = this.fixPrecision(v);
40697 v = String(v).replace(".", this.decimalSeparator);
40703 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40705 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40706 this.thousandsDelimiter || ','
40709 if(this.allowBlank && !v) {
40710 this.inputEl().dom.value = '';
40717 getRawValue : function()
40719 var v = this.inputEl().getValue();
40724 getValue : function()
40726 return this.fixPrecision(this.parseValue(this.getRawValue()));
40729 parseValue : function(value)
40731 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40732 return isNaN(value) ? '' : value;
40735 fixPrecision : function(value)
40737 var nan = isNaN(value);
40739 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40740 return nan ? '' : value;
40743 return parseFloat(value).toFixed(this.decimalPrecision);
40746 decimalPrecisionFcn : function(v)
40748 return Math.floor(v);
40751 validateValue : function(value)
40753 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40757 var num = this.parseValue(value);
40760 this.markInvalid(String.format(this.nanText, value));
40764 if(num < this.minValue){
40765 this.markInvalid(String.format(this.minText, this.minValue));
40769 if(num > this.maxValue){
40770 this.markInvalid(String.format(this.maxText, this.maxValue));
40777 validate : function()
40779 if(this.disabled || this.allowBlank){
40784 var currency = this.getCurrency();
40786 if(this.validateValue(this.getRawValue()) && currency.length){
40791 this.markInvalid();
40795 getName: function()
40800 beforeBlur : function()
40806 var v = this.parseValue(this.getRawValue());
40813 onBlur : function()
40817 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40818 //this.el.removeClass(this.focusClass);
40821 this.hasFocus = false;
40823 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40827 var v = this.getValue();
40829 if(String(v) !== String(this.startValue)){
40830 this.fireEvent('change', this, v, this.startValue);
40833 this.fireEvent("blur", this);
40836 inputEl : function()
40838 return this.el.select('.roo-money-amount-input', true).first();
40841 currencyEl : function()
40843 return this.el.select('.roo-money-currency-input', true).first();
40846 hiddenEl : function()
40848 return this.el.select('input.hidden-number-input',true).first();