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)
21 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24 * Do not use directly - it does not do anything..
25 * @param {Object} config The config object
30 Roo.bootstrap.Component = function(config){
31 Roo.bootstrap.Component.superclass.constructor.call(this, config);
35 * @event childrenrendered
36 * Fires when the children have been rendered..
37 * @param {Roo.bootstrap.Component} this
39 "childrenrendered" : true
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
51 allowDomMove : false, // to stop relocations in parent onRender...
61 * Initialize Events for the element
63 initEvents : function() { },
69 can_build_overlaid : true,
71 container_method : false,
78 // returns the parent component..
79 return Roo.ComponentMgr.get(this.parentId)
85 onRender : function(ct, position)
87 // Roo.log("Call onRender: " + this.xtype);
89 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
92 if (this.el.attr('xtype')) {
93 this.el.attr('xtypex', this.el.attr('xtype'));
94 this.el.dom.removeAttribute('xtype');
104 var cfg = Roo.apply({}, this.getAutoCreate());
106 cfg.id = this.id || Roo.id();
108 // fill in the extra attributes
109 if (this.xattr && typeof(this.xattr) =='object') {
110 for (var i in this.xattr) {
111 cfg[i] = this.xattr[i];
116 cfg.dataId = this.dataId;
120 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
123 if (this.style) { // fixme needs to support more complex style data.
124 cfg.style = this.style;
128 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
166 //Roo.log(['addxtype', cn]);
168 cn.parentType = this.xtype; //??
169 cn.parentId = this.id;
171 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172 if (typeof(cn.container_method) == 'string') {
173 cntr = cn.container_method;
177 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
179 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
181 var build_from_html = Roo.XComponent.build_from_html;
183 var is_body = (tree.xtype == 'Body') ;
185 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
187 var self_cntr_el = Roo.get(this[cntr](false));
189 // do not try and build conditional elements
190 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
194 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196 return this.addxtypeChild(tree,cntr, is_body);
199 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
202 return this.addxtypeChild(Roo.apply({}, tree),cntr);
205 Roo.log('skipping render');
211 if (!build_from_html) {
215 // this i think handles overlaying multiple children of the same type
216 // with the sam eelement.. - which might be buggy..
218 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
224 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
228 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
235 addxtypeChild : function (tree, cntr, is_body)
237 Roo.debug && Roo.log('addxtypeChild:' + cntr);
239 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
242 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243 (typeof(tree['flexy:foreach']) != 'undefined');
247 skip_children = false;
248 // render the element if it's not BODY.
251 // if parent was disabled, then do not try and create the children..
252 if(!this[cntr](true)){
257 cn = Roo.factory(tree);
259 cn.parentType = this.xtype; //??
260 cn.parentId = this.id;
262 var build_from_html = Roo.XComponent.build_from_html;
265 // does the container contain child eleemnts with 'xtype' attributes.
266 // that match this xtype..
267 // note - when we render we create these as well..
268 // so we should check to see if body has xtype set.
269 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
271 var self_cntr_el = Roo.get(this[cntr](false));
272 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
274 //Roo.log(Roo.XComponent.build_from_html);
275 //Roo.log("got echild:");
278 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279 // and are not displayed -this causes this to use up the wrong element when matching.
280 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
283 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
290 //echild.dom.removeAttribute('xtype');
292 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293 Roo.debug && Roo.log(self_cntr_el);
294 Roo.debug && Roo.log(echild);
295 Roo.debug && Roo.log(cn);
301 // if object has flexy:if - then it may or may not be rendered.
302 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
303 // skip a flexy if element.
304 Roo.debug && Roo.log('skipping render');
305 Roo.debug && Roo.log(tree);
307 Roo.debug && Roo.log('skipping all children');
308 skip_children = true;
313 // actually if flexy:foreach is found, we really want to create
314 // multiple copies here...
316 //Roo.log(this[cntr]());
317 // some elements do not have render methods.. like the layouts...
319 if(this[cntr](true) === false){
324 cn.render && cn.render(this[cntr](true));
327 // then add the element..
334 if (typeof (tree.menu) != 'undefined') {
335 tree.menu.parentType = cn.xtype;
336 tree.menu.triggerEl = cn.el;
337 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
341 if (!tree.items || !tree.items.length) {
343 //Roo.log(["no children", this]);
348 var items = tree.items;
351 //Roo.log(items.length);
353 if (!skip_children) {
354 for(var i =0;i < items.length;i++) {
355 // Roo.log(['add child', items[i]]);
356 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
362 //Roo.log("fire childrenrendered");
364 cn.fireEvent('childrenrendered', this);
370 * Set the element that will be used to show or hide
372 setVisibilityEl : function(el)
374 this.visibilityEl = el;
378 * Get the element that will be used to show or hide
380 getVisibilityEl : function()
382 if (typeof(this.visibilityEl) == 'object') {
383 return this.visibilityEl;
386 if (typeof(this.visibilityEl) == 'string') {
387 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
394 * Show a component - removes 'hidden' class
398 if(!this.getVisibilityEl()){
402 this.getVisibilityEl().removeClass('hidden');
407 * Hide a component - adds 'hidden' class
411 if(!this.getVisibilityEl()){
415 this.getVisibilityEl().addClass('hidden');
428 * @class Roo.bootstrap.Body
429 * @extends Roo.bootstrap.Component
430 * Bootstrap Body class
434 * @param {Object} config The config object
437 Roo.bootstrap.Body = function(config){
439 config = config || {};
441 Roo.bootstrap.Body.superclass.constructor.call(this, config);
442 this.el = Roo.get(config.el ? config.el : document.body );
443 if (this.cls && this.cls.length) {
444 Roo.get(document.body).addClass(this.cls);
448 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
450 is_body : true,// just to make sure it's constructed?
455 onRender : function(ct, position)
457 /* Roo.log("Roo.bootstrap.Body - onRender");
458 if (this.cls && this.cls.length) {
459 Roo.get(document.body).addClass(this.cls);
478 * @class Roo.bootstrap.ButtonGroup
479 * @extends Roo.bootstrap.Component
480 * Bootstrap ButtonGroup class
481 * @cfg {String} size lg | sm | xs (default empty normal)
482 * @cfg {String} align vertical | justified (default none)
483 * @cfg {String} direction up | down (default down)
484 * @cfg {Boolean} toolbar false | true
485 * @cfg {Boolean} btn true | false
490 * @param {Object} config The config object
493 Roo.bootstrap.ButtonGroup = function(config){
494 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
497 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
505 getAutoCreate : function(){
511 cfg.html = this.html || cfg.html;
522 if (['vertical','justified'].indexOf(this.align)!==-1) {
523 cfg.cls = 'btn-group-' + this.align;
525 if (this.align == 'justified') {
526 console.log(this.items);
530 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
531 cfg.cls += ' btn-group-' + this.size;
534 if (this.direction == 'up') {
535 cfg.cls += ' dropup' ;
551 * @class Roo.bootstrap.Button
552 * @extends Roo.bootstrap.Component
553 * Bootstrap Button class
554 * @cfg {String} html The button content
555 * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default
556 * @cfg {String} size ( lg | sm | xs)
557 * @cfg {String} tag ( a | input | submit)
558 * @cfg {String} href empty or href
559 * @cfg {Boolean} disabled default false;
560 * @cfg {Boolean} isClose default false;
561 * @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)
562 * @cfg {String} badge text for badge
563 * @cfg {String} theme default
564 * @cfg {Boolean} inverse
565 * @cfg {Boolean} toggle is it a slidy toggle button
566 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
567 * @cfg {String} ontext text for on toggle state
568 * @cfg {String} offtext text for off toggle state
569 * @cfg {Boolean} defaulton
570 * @cfg {Boolean} preventDefault default true
571 * @cfg {Boolean} removeClass remove the standard class..
572 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
575 * Create a new button
576 * @param {Object} config The config object
580 Roo.bootstrap.Button = function(config){
581 Roo.bootstrap.Button.superclass.constructor.call(this, config);
582 this.weightClass = ["btn-default",
594 * When a butotn is pressed
595 * @param {Roo.bootstrap.Button} btn
596 * @param {Roo.EventObject} e
601 * After the button has been toggles
602 * @param {Roo.bootstrap.Button} btn
603 * @param {Roo.EventObject} e
604 * @param {boolean} pressed (also available as button.pressed)
610 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
628 preventDefault: true,
637 getAutoCreate : function(){
645 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
646 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
651 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
653 if (this.toggle == true) {
656 cls: 'slider-frame roo-button',
661 'data-off-text':'OFF',
662 cls: 'slider-button',
668 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
669 cfg.cls += ' '+this.weight;
678 cfg["aria-hidden"] = true;
680 cfg.html = "×";
686 if (this.theme==='default') {
687 cfg.cls = 'btn roo-button';
689 //if (this.parentType != 'Navbar') {
690 this.weight = this.weight.length ? this.weight : 'default';
692 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
694 cfg.cls += ' btn-' + this.weight;
696 } else if (this.theme==='glow') {
699 cfg.cls = 'btn-glow roo-button';
701 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
703 cfg.cls += ' ' + this.weight;
709 this.cls += ' inverse';
713 if (this.active || this.pressed === true) {
714 cfg.cls += ' active';
718 cfg.disabled = 'disabled';
722 Roo.log('changing to ul' );
724 this.glyphicon = 'caret';
727 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
729 //gsRoo.log(this.parentType);
730 if (this.parentType === 'Navbar' && !this.parent().bar) {
731 Roo.log('changing to li?');
740 href : this.href || '#'
743 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
744 cfg.cls += ' dropdown';
751 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
753 if (this.glyphicon) {
754 cfg.html = ' ' + cfg.html;
759 cls: 'glyphicon glyphicon-' + this.glyphicon
769 // cfg.cls='btn roo-button';
773 var value = cfg.html;
778 cls: 'glyphicon glyphicon-' + this.glyphicon,
797 cfg.cls += ' dropdown';
798 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
801 if (cfg.tag !== 'a' && this.href !== '') {
802 throw "Tag must be a to set href.";
803 } else if (this.href.length > 0) {
804 cfg.href = this.href;
807 if(this.removeClass){
812 cfg.target = this.target;
817 initEvents: function() {
818 // Roo.log('init events?');
819 // Roo.log(this.el.dom);
822 if (typeof (this.menu) != 'undefined') {
823 this.menu.parentType = this.xtype;
824 this.menu.triggerEl = this.el;
825 this.addxtype(Roo.apply({}, this.menu));
829 if (this.el.hasClass('roo-button')) {
830 this.el.on('click', this.onClick, this);
832 this.el.select('.roo-button').on('click', this.onClick, this);
835 if(this.removeClass){
836 this.el.on('click', this.onClick, this);
839 this.el.enableDisplayMode();
842 onClick : function(e)
849 Roo.log('button on click ');
850 if(this.preventDefault){
854 if (this.pressed === true || this.pressed === false) {
855 this.pressed = !this.pressed;
856 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
857 this.fireEvent('toggle', this, e, this.pressed);
861 this.fireEvent('click', this, e);
865 * Enables this button
869 this.disabled = false;
870 this.el.removeClass('disabled');
874 * Disable this button
878 this.disabled = true;
879 this.el.addClass('disabled');
882 * sets the active state on/off,
883 * @param {Boolean} state (optional) Force a particular state
885 setActive : function(v) {
887 this.el[v ? 'addClass' : 'removeClass']('active');
891 * toggles the current active state
893 toggleActive : function()
895 var active = this.el.hasClass('active');
896 this.setActive(!active);
901 * get the current active state
902 * @return {boolean} true if it's active
904 isActive : function()
906 return this.el.hasClass('active');
909 * set the text of the first selected button
911 setText : function(str)
913 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
916 * get the text of the first selected button
920 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
931 setWeight : function(str)
933 this.el.removeClass(this.weightClass);
934 this.el.addClass('btn-' + str);
948 * @class Roo.bootstrap.Column
949 * @extends Roo.bootstrap.Component
950 * Bootstrap Column class
951 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
952 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
953 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
954 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
955 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
956 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
957 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
958 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
961 * @cfg {Boolean} hidden (true|false) hide the element
962 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
963 * @cfg {String} fa (ban|check|...) font awesome icon
964 * @cfg {Number} fasize (1|2|....) font awsome size
966 * @cfg {String} icon (info-sign|check|...) glyphicon name
968 * @cfg {String} html content of column.
971 * Create a new Column
972 * @param {Object} config The config object
975 Roo.bootstrap.Column = function(config){
976 Roo.bootstrap.Column.superclass.constructor.call(this, config);
979 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
997 getAutoCreate : function(){
998 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1006 ['xs','sm','md','lg'].map(function(size){
1007 //Roo.log( size + ':' + settings[size]);
1009 if (settings[size+'off'] !== false) {
1010 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1013 if (settings[size] === false) {
1017 if (!settings[size]) { // 0 = hidden
1018 cfg.cls += ' hidden-' + size;
1021 cfg.cls += ' col-' + size + '-' + settings[size];
1026 cfg.cls += ' hidden';
1029 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1030 cfg.cls +=' alert alert-' + this.alert;
1034 if (this.html.length) {
1035 cfg.html = this.html;
1039 if (this.fasize > 1) {
1040 fasize = ' fa-' + this.fasize + 'x';
1042 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1047 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1066 * @class Roo.bootstrap.Container
1067 * @extends Roo.bootstrap.Component
1068 * Bootstrap Container class
1069 * @cfg {Boolean} jumbotron is it a jumbotron element
1070 * @cfg {String} html content of element
1071 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1072 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1073 * @cfg {String} header content of header (for panel)
1074 * @cfg {String} footer content of footer (for panel)
1075 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1076 * @cfg {String} tag (header|aside|section) type of HTML tag.
1077 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1078 * @cfg {String} fa font awesome icon
1079 * @cfg {String} icon (info-sign|check|...) glyphicon name
1080 * @cfg {Boolean} hidden (true|false) hide the element
1081 * @cfg {Boolean} expandable (true|false) default false
1082 * @cfg {Boolean} expanded (true|false) default true
1083 * @cfg {String} rheader contet on the right of header
1084 * @cfg {Boolean} clickable (true|false) default false
1088 * Create a new Container
1089 * @param {Object} config The config object
1092 Roo.bootstrap.Container = function(config){
1093 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1099 * After the panel has been expand
1101 * @param {Roo.bootstrap.Container} this
1106 * After the panel has been collapsed
1108 * @param {Roo.bootstrap.Container} this
1113 * When a element is chick
1114 * @param {Roo.bootstrap.Container} this
1115 * @param {Roo.EventObject} e
1121 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1139 getChildContainer : function() {
1145 if (this.panel.length) {
1146 return this.el.select('.panel-body',true).first();
1153 getAutoCreate : function(){
1156 tag : this.tag || 'div',
1160 if (this.jumbotron) {
1161 cfg.cls = 'jumbotron';
1166 // - this is applied by the parent..
1168 // cfg.cls = this.cls + '';
1171 if (this.sticky.length) {
1173 var bd = Roo.get(document.body);
1174 if (!bd.hasClass('bootstrap-sticky')) {
1175 bd.addClass('bootstrap-sticky');
1176 Roo.select('html',true).setStyle('height', '100%');
1179 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1183 if (this.well.length) {
1184 switch (this.well) {
1187 cfg.cls +=' well well-' +this.well;
1196 cfg.cls += ' hidden';
1200 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1201 cfg.cls +=' alert alert-' + this.alert;
1206 if (this.panel.length) {
1207 cfg.cls += ' panel panel-' + this.panel;
1209 if (this.header.length) {
1213 if(this.expandable){
1215 cfg.cls = cfg.cls + ' expandable';
1219 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1227 cls : 'panel-title',
1228 html : (this.expandable ? ' ' : '') + this.header
1232 cls: 'panel-header-right',
1238 cls : 'panel-heading',
1239 style : this.expandable ? 'cursor: pointer' : '',
1247 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1252 if (this.footer.length) {
1254 cls : 'panel-footer',
1263 body.html = this.html || cfg.html;
1264 // prefix with the icons..
1266 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1269 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1274 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1275 cfg.cls = 'container';
1281 initEvents: function()
1283 if(this.expandable){
1284 var headerEl = this.headerEl();
1287 headerEl.on('click', this.onToggleClick, this);
1292 this.el.on('click', this.onClick, this);
1297 onToggleClick : function()
1299 var headerEl = this.headerEl();
1315 if(this.fireEvent('expand', this)) {
1317 this.expanded = true;
1319 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1321 this.el.select('.panel-body',true).first().removeClass('hide');
1323 var toggleEl = this.toggleEl();
1329 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1334 collapse : function()
1336 if(this.fireEvent('collapse', this)) {
1338 this.expanded = false;
1340 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1341 this.el.select('.panel-body',true).first().addClass('hide');
1343 var toggleEl = this.toggleEl();
1349 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1353 toggleEl : function()
1355 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1359 return this.el.select('.panel-heading .fa',true).first();
1362 headerEl : function()
1364 if(!this.el || !this.panel.length || !this.header.length){
1368 return this.el.select('.panel-heading',true).first()
1373 if(!this.el || !this.panel.length){
1377 return this.el.select('.panel-body',true).first()
1380 titleEl : function()
1382 if(!this.el || !this.panel.length || !this.header.length){
1386 return this.el.select('.panel-title',true).first();
1389 setTitle : function(v)
1391 var titleEl = this.titleEl();
1397 titleEl.dom.innerHTML = v;
1400 getTitle : function()
1403 var titleEl = this.titleEl();
1409 return titleEl.dom.innerHTML;
1412 setRightTitle : function(v)
1414 var t = this.el.select('.panel-header-right',true).first();
1420 t.dom.innerHTML = v;
1423 onClick : function(e)
1427 this.fireEvent('click', this, e);
1440 * @class Roo.bootstrap.Img
1441 * @extends Roo.bootstrap.Component
1442 * Bootstrap Img class
1443 * @cfg {Boolean} imgResponsive false | true
1444 * @cfg {String} border rounded | circle | thumbnail
1445 * @cfg {String} src image source
1446 * @cfg {String} alt image alternative text
1447 * @cfg {String} href a tag href
1448 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1449 * @cfg {String} xsUrl xs image source
1450 * @cfg {String} smUrl sm image source
1451 * @cfg {String} mdUrl md image source
1452 * @cfg {String} lgUrl lg image source
1455 * Create a new Input
1456 * @param {Object} config The config object
1459 Roo.bootstrap.Img = function(config){
1460 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1466 * The img click event for the img.
1467 * @param {Roo.EventObject} e
1473 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1475 imgResponsive: true,
1485 getAutoCreate : function()
1487 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1488 return this.createSingleImg();
1493 cls: 'roo-image-responsive-group',
1498 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1500 if(!_this[size + 'Url']){
1506 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1507 html: _this.html || cfg.html,
1508 src: _this[size + 'Url']
1511 img.cls += ' roo-image-responsive-' + size;
1513 var s = ['xs', 'sm', 'md', 'lg'];
1515 s.splice(s.indexOf(size), 1);
1517 Roo.each(s, function(ss){
1518 img.cls += ' hidden-' + ss;
1521 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1522 cfg.cls += ' img-' + _this.border;
1526 cfg.alt = _this.alt;
1539 a.target = _this.target;
1543 cfg.cn.push((_this.href) ? a : img);
1550 createSingleImg : function()
1554 cls: (this.imgResponsive) ? 'img-responsive' : '',
1556 src : 'about:blank' // just incase src get's set to undefined?!?
1559 cfg.html = this.html || cfg.html;
1561 cfg.src = this.src || cfg.src;
1563 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1564 cfg.cls += ' img-' + this.border;
1581 a.target = this.target;
1586 return (this.href) ? a : cfg;
1589 initEvents: function()
1592 this.el.on('click', this.onClick, this);
1597 onClick : function(e)
1599 Roo.log('img onclick');
1600 this.fireEvent('click', this, e);
1603 * Sets the url of the image - used to update it
1604 * @param {String} url the url of the image
1607 setSrc : function(url)
1611 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1612 this.el.dom.src = url;
1616 this.el.select('img', true).first().dom.src = url;
1632 * @class Roo.bootstrap.Link
1633 * @extends Roo.bootstrap.Component
1634 * Bootstrap Link Class
1635 * @cfg {String} alt image alternative text
1636 * @cfg {String} href a tag href
1637 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1638 * @cfg {String} html the content of the link.
1639 * @cfg {String} anchor name for the anchor link
1640 * @cfg {String} fa - favicon
1642 * @cfg {Boolean} preventDefault (true | false) default false
1646 * Create a new Input
1647 * @param {Object} config The config object
1650 Roo.bootstrap.Link = function(config){
1651 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1657 * The img click event for the img.
1658 * @param {Roo.EventObject} e
1664 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1668 preventDefault: false,
1674 getAutoCreate : function()
1676 var html = this.html || '';
1678 if (this.fa !== false) {
1679 html = '<i class="fa fa-' + this.fa + '"></i>';
1684 // anchor's do not require html/href...
1685 if (this.anchor === false) {
1687 cfg.href = this.href || '#';
1689 cfg.name = this.anchor;
1690 if (this.html !== false || this.fa !== false) {
1693 if (this.href !== false) {
1694 cfg.href = this.href;
1698 if(this.alt !== false){
1703 if(this.target !== false) {
1704 cfg.target = this.target;
1710 initEvents: function() {
1712 if(!this.href || this.preventDefault){
1713 this.el.on('click', this.onClick, this);
1717 onClick : function(e)
1719 if(this.preventDefault){
1722 //Roo.log('img onclick');
1723 this.fireEvent('click', this, e);
1736 * @class Roo.bootstrap.Header
1737 * @extends Roo.bootstrap.Component
1738 * Bootstrap Header class
1739 * @cfg {String} html content of header
1740 * @cfg {Number} level (1|2|3|4|5|6) default 1
1743 * Create a new Header
1744 * @param {Object} config The config object
1748 Roo.bootstrap.Header = function(config){
1749 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1752 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1760 getAutoCreate : function(){
1765 tag: 'h' + (1 *this.level),
1766 html: this.html || ''
1778 * Ext JS Library 1.1.1
1779 * Copyright(c) 2006-2007, Ext JS, LLC.
1781 * Originally Released Under LGPL - original licence link has changed is not relivant.
1784 * <script type="text/javascript">
1788 * @class Roo.bootstrap.MenuMgr
1789 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1792 Roo.bootstrap.MenuMgr = function(){
1793 var menus, active, groups = {}, attached = false, lastShow = new Date();
1795 // private - called when first menu is created
1798 active = new Roo.util.MixedCollection();
1799 Roo.get(document).addKeyListener(27, function(){
1800 if(active.length > 0){
1808 if(active && active.length > 0){
1809 var c = active.clone();
1819 if(active.length < 1){
1820 Roo.get(document).un("mouseup", onMouseDown);
1828 var last = active.last();
1829 lastShow = new Date();
1832 Roo.get(document).on("mouseup", onMouseDown);
1837 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1838 m.parentMenu.activeChild = m;
1839 }else if(last && last.isVisible()){
1840 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1845 function onBeforeHide(m){
1847 m.activeChild.hide();
1849 if(m.autoHideTimer){
1850 clearTimeout(m.autoHideTimer);
1851 delete m.autoHideTimer;
1856 function onBeforeShow(m){
1857 var pm = m.parentMenu;
1858 if(!pm && !m.allowOtherMenus){
1860 }else if(pm && pm.activeChild && active != m){
1861 pm.activeChild.hide();
1865 // private this should really trigger on mouseup..
1866 function onMouseDown(e){
1867 Roo.log("on Mouse Up");
1869 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1870 Roo.log("MenuManager hideAll");
1879 function onBeforeCheck(mi, state){
1881 var g = groups[mi.group];
1882 for(var i = 0, l = g.length; i < l; i++){
1884 g[i].setChecked(false);
1893 * Hides all menus that are currently visible
1895 hideAll : function(){
1900 register : function(menu){
1904 menus[menu.id] = menu;
1905 menu.on("beforehide", onBeforeHide);
1906 menu.on("hide", onHide);
1907 menu.on("beforeshow", onBeforeShow);
1908 menu.on("show", onShow);
1910 if(g && menu.events["checkchange"]){
1914 groups[g].push(menu);
1915 menu.on("checkchange", onCheck);
1920 * Returns a {@link Roo.menu.Menu} object
1921 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1922 * be used to generate and return a new Menu instance.
1924 get : function(menu){
1925 if(typeof menu == "string"){ // menu id
1927 }else if(menu.events){ // menu instance
1930 /*else if(typeof menu.length == 'number'){ // array of menu items?
1931 return new Roo.bootstrap.Menu({items:menu});
1932 }else{ // otherwise, must be a config
1933 return new Roo.bootstrap.Menu(menu);
1940 unregister : function(menu){
1941 delete menus[menu.id];
1942 menu.un("beforehide", onBeforeHide);
1943 menu.un("hide", onHide);
1944 menu.un("beforeshow", onBeforeShow);
1945 menu.un("show", onShow);
1947 if(g && menu.events["checkchange"]){
1948 groups[g].remove(menu);
1949 menu.un("checkchange", onCheck);
1954 registerCheckable : function(menuItem){
1955 var g = menuItem.group;
1960 groups[g].push(menuItem);
1961 menuItem.on("beforecheckchange", onBeforeCheck);
1966 unregisterCheckable : function(menuItem){
1967 var g = menuItem.group;
1969 groups[g].remove(menuItem);
1970 menuItem.un("beforecheckchange", onBeforeCheck);
1982 * @class Roo.bootstrap.Menu
1983 * @extends Roo.bootstrap.Component
1984 * Bootstrap Menu class - container for MenuItems
1985 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1986 * @cfg {bool} hidden if the menu should be hidden when rendered.
1987 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
1988 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
1992 * @param {Object} config The config object
1996 Roo.bootstrap.Menu = function(config){
1997 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1998 if (this.registerMenu && this.type != 'treeview') {
1999 Roo.bootstrap.MenuMgr.register(this);
2004 * Fires before this menu is displayed
2005 * @param {Roo.menu.Menu} this
2010 * Fires before this menu is hidden
2011 * @param {Roo.menu.Menu} this
2016 * Fires after this menu is displayed
2017 * @param {Roo.menu.Menu} this
2022 * Fires after this menu is hidden
2023 * @param {Roo.menu.Menu} this
2028 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2029 * @param {Roo.menu.Menu} this
2030 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2031 * @param {Roo.EventObject} e
2036 * Fires when the mouse is hovering over this menu
2037 * @param {Roo.menu.Menu} this
2038 * @param {Roo.EventObject} e
2039 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2044 * Fires when the mouse exits this menu
2045 * @param {Roo.menu.Menu} this
2046 * @param {Roo.EventObject} e
2047 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2052 * Fires when a menu item contained in this menu is clicked
2053 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2054 * @param {Roo.EventObject} e
2058 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2061 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2065 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2068 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2070 registerMenu : true,
2072 menuItems :false, // stores the menu items..
2082 getChildContainer : function() {
2086 getAutoCreate : function(){
2088 //if (['right'].indexOf(this.align)!==-1) {
2089 // cfg.cn[1].cls += ' pull-right'
2095 cls : 'dropdown-menu' ,
2096 style : 'z-index:1000'
2100 if (this.type === 'submenu') {
2101 cfg.cls = 'submenu active';
2103 if (this.type === 'treeview') {
2104 cfg.cls = 'treeview-menu';
2109 initEvents : function() {
2111 // Roo.log("ADD event");
2112 // Roo.log(this.triggerEl.dom);
2114 this.triggerEl.on('click', this.onTriggerClick, this);
2116 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2118 this.triggerEl.addClass('dropdown-toggle');
2121 this.el.on('touchstart' , this.onTouch, this);
2123 this.el.on('click' , this.onClick, this);
2125 this.el.on("mouseover", this.onMouseOver, this);
2126 this.el.on("mouseout", this.onMouseOut, this);
2130 findTargetItem : function(e)
2132 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2136 //Roo.log(t); Roo.log(t.id);
2138 //Roo.log(this.menuitems);
2139 return this.menuitems.get(t.id);
2141 //return this.items.get(t.menuItemId);
2147 onTouch : function(e)
2149 Roo.log("menu.onTouch");
2150 //e.stopEvent(); this make the user popdown broken
2154 onClick : function(e)
2156 Roo.log("menu.onClick");
2158 var t = this.findTargetItem(e);
2159 if(!t || t.isContainer){
2164 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2165 if(t == this.activeItem && t.shouldDeactivate(e)){
2166 this.activeItem.deactivate();
2167 delete this.activeItem;
2171 this.setActiveItem(t, true);
2179 Roo.log('pass click event');
2183 this.fireEvent("click", this, t, e);
2187 if(!t.href.length || t.href == '#'){
2188 (function() { _this.hide(); }).defer(100);
2193 onMouseOver : function(e){
2194 var t = this.findTargetItem(e);
2197 // if(t.canActivate && !t.disabled){
2198 // this.setActiveItem(t, true);
2202 this.fireEvent("mouseover", this, e, t);
2204 isVisible : function(){
2205 return !this.hidden;
2207 onMouseOut : function(e){
2208 var t = this.findTargetItem(e);
2211 // if(t == this.activeItem && t.shouldDeactivate(e)){
2212 // this.activeItem.deactivate();
2213 // delete this.activeItem;
2216 this.fireEvent("mouseout", this, e, t);
2221 * Displays this menu relative to another element
2222 * @param {String/HTMLElement/Roo.Element} element The element to align to
2223 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2224 * the element (defaults to this.defaultAlign)
2225 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2227 show : function(el, pos, parentMenu){
2228 this.parentMenu = parentMenu;
2232 this.fireEvent("beforeshow", this);
2233 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2236 * Displays this menu at a specific xy position
2237 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2238 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2240 showAt : function(xy, parentMenu, /* private: */_e){
2241 this.parentMenu = parentMenu;
2246 this.fireEvent("beforeshow", this);
2247 //xy = this.el.adjustForConstraints(xy);
2251 this.hideMenuItems();
2252 this.hidden = false;
2253 this.triggerEl.addClass('open');
2255 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2256 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2259 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2264 this.fireEvent("show", this);
2270 this.doFocus.defer(50, this);
2274 doFocus : function(){
2276 this.focusEl.focus();
2281 * Hides this menu and optionally all parent menus
2282 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2284 hide : function(deep)
2287 this.hideMenuItems();
2288 if(this.el && this.isVisible()){
2289 this.fireEvent("beforehide", this);
2290 if(this.activeItem){
2291 this.activeItem.deactivate();
2292 this.activeItem = null;
2294 this.triggerEl.removeClass('open');;
2296 this.fireEvent("hide", this);
2298 if(deep === true && this.parentMenu){
2299 this.parentMenu.hide(true);
2303 onTriggerClick : function(e)
2305 Roo.log('trigger click');
2307 var target = e.getTarget();
2309 Roo.log(target.nodeName.toLowerCase());
2311 if(target.nodeName.toLowerCase() === 'i'){
2317 onTriggerPress : function(e)
2319 Roo.log('trigger press');
2320 //Roo.log(e.getTarget());
2321 // Roo.log(this.triggerEl.dom);
2323 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2324 var pel = Roo.get(e.getTarget());
2325 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2326 Roo.log('is treeview or dropdown?');
2330 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2334 if (this.isVisible()) {
2339 this.show(this.triggerEl, false, false);
2342 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2349 hideMenuItems : function()
2351 Roo.log("hide Menu Items");
2355 //$(backdrop).remove()
2356 this.el.select('.open',true).each(function(aa) {
2358 aa.removeClass('open');
2359 //var parent = getParent($(this))
2360 //var relatedTarget = { relatedTarget: this }
2362 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2363 //if (e.isDefaultPrevented()) return
2364 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2367 addxtypeChild : function (tree, cntr) {
2368 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2370 this.menuitems.add(comp);
2382 this.getEl().dom.innerHTML = '';
2383 this.menuitems.clear();
2397 * @class Roo.bootstrap.MenuItem
2398 * @extends Roo.bootstrap.Component
2399 * Bootstrap MenuItem class
2400 * @cfg {String} html the menu label
2401 * @cfg {String} href the link
2402 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2403 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2404 * @cfg {Boolean} active used on sidebars to highlight active itesm
2405 * @cfg {String} fa favicon to show on left of menu item.
2406 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2410 * Create a new MenuItem
2411 * @param {Object} config The config object
2415 Roo.bootstrap.MenuItem = function(config){
2416 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2421 * The raw click event for the entire grid.
2422 * @param {Roo.bootstrap.MenuItem} this
2423 * @param {Roo.EventObject} e
2429 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2433 preventDefault: false,
2434 isContainer : false,
2438 getAutoCreate : function(){
2440 if(this.isContainer){
2443 cls: 'dropdown-menu-item'
2457 if (this.fa !== false) {
2460 cls : 'fa fa-' + this.fa
2469 cls: 'dropdown-menu-item',
2472 if (this.parent().type == 'treeview') {
2473 cfg.cls = 'treeview-menu';
2476 cfg.cls += ' active';
2481 anc.href = this.href || cfg.cn[0].href ;
2482 ctag.html = this.html || cfg.cn[0].html ;
2486 initEvents: function()
2488 if (this.parent().type == 'treeview') {
2489 this.el.select('a').on('click', this.onClick, this);
2493 this.menu.parentType = this.xtype;
2494 this.menu.triggerEl = this.el;
2495 this.menu = this.addxtype(Roo.apply({}, this.menu));
2499 onClick : function(e)
2501 Roo.log('item on click ');
2503 if(this.preventDefault){
2506 //this.parent().hideMenuItems();
2508 this.fireEvent('click', this, e);
2527 * @class Roo.bootstrap.MenuSeparator
2528 * @extends Roo.bootstrap.Component
2529 * Bootstrap MenuSeparator class
2532 * Create a new MenuItem
2533 * @param {Object} config The config object
2537 Roo.bootstrap.MenuSeparator = function(config){
2538 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2541 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2543 getAutoCreate : function(){
2562 * @class Roo.bootstrap.Modal
2563 * @extends Roo.bootstrap.Component
2564 * Bootstrap Modal class
2565 * @cfg {String} title Title of dialog
2566 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2567 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2568 * @cfg {Boolean} specificTitle default false
2569 * @cfg {Array} buttons Array of buttons or standard button set..
2570 * @cfg {String} buttonPosition (left|right|center) default right
2571 * @cfg {Boolean} animate default true
2572 * @cfg {Boolean} allow_close default true
2573 * @cfg {Boolean} fitwindow default false
2574 * @cfg {String} size (sm|lg) default empty
2578 * Create a new Modal Dialog
2579 * @param {Object} config The config object
2582 Roo.bootstrap.Modal = function(config){
2583 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2588 * The raw btnclick event for the button
2589 * @param {Roo.EventObject} e
2594 * Fire when dialog resize
2595 * @param {Roo.bootstrap.Modal} this
2596 * @param {Roo.EventObject} e
2600 this.buttons = this.buttons || [];
2603 this.tmpl = Roo.factory(this.tmpl);
2608 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2610 title : 'test dialog',
2620 specificTitle: false,
2622 buttonPosition: 'right',
2641 onRender : function(ct, position)
2643 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2646 var cfg = Roo.apply({}, this.getAutoCreate());
2649 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2651 //if (!cfg.name.length) {
2655 cfg.cls += ' ' + this.cls;
2658 cfg.style = this.style;
2660 this.el = Roo.get(document.body).createChild(cfg, position);
2662 //var type = this.el.dom.type;
2665 if(this.tabIndex !== undefined){
2666 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2669 this.dialogEl = this.el.select('.modal-dialog',true).first();
2670 this.bodyEl = this.el.select('.modal-body',true).first();
2671 this.closeEl = this.el.select('.modal-header .close', true).first();
2672 this.headerEl = this.el.select('.modal-header',true).first();
2673 this.titleEl = this.el.select('.modal-title',true).first();
2674 this.footerEl = this.el.select('.modal-footer',true).first();
2676 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2677 this.maskEl.enableDisplayMode("block");
2679 //this.el.addClass("x-dlg-modal");
2681 if (this.buttons.length) {
2682 Roo.each(this.buttons, function(bb) {
2683 var b = Roo.apply({}, bb);
2684 b.xns = b.xns || Roo.bootstrap;
2685 b.xtype = b.xtype || 'Button';
2686 if (typeof(b.listeners) == 'undefined') {
2687 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2690 var btn = Roo.factory(b);
2692 btn.render(this.el.select('.modal-footer div').first());
2696 // render the children.
2699 if(typeof(this.items) != 'undefined'){
2700 var items = this.items;
2703 for(var i =0;i < items.length;i++) {
2704 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2708 this.items = nitems;
2710 // where are these used - they used to be body/close/footer
2714 //this.el.addClass([this.fieldClass, this.cls]);
2718 getAutoCreate : function(){
2723 html : this.html || ''
2728 cls : 'modal-title',
2732 if(this.specificTitle){
2738 if (this.allow_close) {
2750 if(this.size.length){
2751 size = 'modal-' + this.size;
2756 style : 'display: none',
2759 cls: "modal-dialog " + size,
2762 cls : "modal-content",
2765 cls : 'modal-header',
2770 cls : 'modal-footer',
2774 cls: 'btn-' + this.buttonPosition
2791 modal.cls += ' fade';
2797 getChildContainer : function() {
2802 getButtonContainer : function() {
2803 return this.el.select('.modal-footer div',true).first();
2806 initEvents : function()
2808 if (this.allow_close) {
2809 this.closeEl.on('click', this.hide, this);
2811 Roo.EventManager.onWindowResize(this.resize, this, true);
2818 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2819 if (this.fitwindow) {
2820 var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2821 var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2826 setSize : function(w,h)
2836 if (!this.rendered) {
2840 this.el.setStyle('display', 'block');
2842 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2845 this.el.addClass('in');
2848 this.el.addClass('in');
2852 // not sure how we can show data in here..
2854 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2857 Roo.get(document.body).addClass("x-body-masked");
2859 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2860 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2865 this.fireEvent('show', this);
2867 // set zindex here - otherwise it appears to be ignored...
2868 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2871 this.items.forEach( function(e) {
2872 e.layout ? e.layout() : false;
2880 if(this.fireEvent("beforehide", this) !== false){
2882 Roo.get(document.body).removeClass("x-body-masked");
2883 this.el.removeClass('in');
2884 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2886 if(this.animate){ // why
2888 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2890 this.el.setStyle('display', 'none');
2892 this.fireEvent('hide', this);
2896 addButton : function(str, cb)
2900 var b = Roo.apply({}, { html : str } );
2901 b.xns = b.xns || Roo.bootstrap;
2902 b.xtype = b.xtype || 'Button';
2903 if (typeof(b.listeners) == 'undefined') {
2904 b.listeners = { click : cb.createDelegate(this) };
2907 var btn = Roo.factory(b);
2909 btn.render(this.el.select('.modal-footer div').first());
2915 setDefaultButton : function(btn)
2917 //this.el.select('.modal-footer').()
2921 resizeTo: function(w,h)
2925 this.dialogEl.setWidth(w);
2926 if (this.diff === false) {
2927 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2930 this.bodyEl.setHeight(h-this.diff);
2932 this.fireEvent('resize', this);
2935 setContentSize : function(w, h)
2939 onButtonClick: function(btn,e)
2942 this.fireEvent('btnclick', btn.name, e);
2945 * Set the title of the Dialog
2946 * @param {String} str new Title
2948 setTitle: function(str) {
2949 this.titleEl.dom.innerHTML = str;
2952 * Set the body of the Dialog
2953 * @param {String} str new Title
2955 setBody: function(str) {
2956 this.bodyEl.dom.innerHTML = str;
2959 * Set the body of the Dialog using the template
2960 * @param {Obj} data - apply this data to the template and replace the body contents.
2962 applyBody: function(obj)
2965 Roo.log("Error - using apply Body without a template");
2968 this.tmpl.overwrite(this.bodyEl, obj);
2974 Roo.apply(Roo.bootstrap.Modal, {
2976 * Button config that displays a single OK button
2985 * Button config that displays Yes and No buttons
3001 * Button config that displays OK and Cancel buttons
3016 * Button config that displays Yes, No and Cancel buttons
3040 * messagebox - can be used as a replace
3044 * @class Roo.MessageBox
3045 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3049 Roo.Msg.alert('Status', 'Changes saved successfully.');
3051 // Prompt for user data:
3052 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3054 // process text value...
3058 // Show a dialog using config options:
3060 title:'Save Changes?',
3061 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3062 buttons: Roo.Msg.YESNOCANCEL,
3069 Roo.bootstrap.MessageBox = function(){
3070 var dlg, opt, mask, waitTimer;
3071 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3072 var buttons, activeTextEl, bwidth;
3076 var handleButton = function(button){
3078 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3082 var handleHide = function(){
3084 dlg.el.removeClass(opt.cls);
3087 // Roo.TaskMgr.stop(waitTimer);
3088 // waitTimer = null;
3093 var updateButtons = function(b){
3096 buttons["ok"].hide();
3097 buttons["cancel"].hide();
3098 buttons["yes"].hide();
3099 buttons["no"].hide();
3100 //dlg.footer.dom.style.display = 'none';
3103 dlg.footerEl.dom.style.display = '';
3104 for(var k in buttons){
3105 if(typeof buttons[k] != "function"){
3108 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3109 width += buttons[k].el.getWidth()+15;
3119 var handleEsc = function(d, k, e){
3120 if(opt && opt.closable !== false){
3130 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3131 * @return {Roo.BasicDialog} The BasicDialog element
3133 getDialog : function(){
3135 dlg = new Roo.bootstrap.Modal( {
3138 //constraintoviewport:false,
3140 //collapsible : false,
3145 //buttonAlign:"center",
3146 closeClick : function(){
3147 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3150 handleButton("cancel");
3155 dlg.on("hide", handleHide);
3157 //dlg.addKeyListener(27, handleEsc);
3159 this.buttons = buttons;
3160 var bt = this.buttonText;
3161 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3162 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3163 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3164 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3166 bodyEl = dlg.bodyEl.createChild({
3168 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3169 '<textarea class="roo-mb-textarea"></textarea>' +
3170 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3172 msgEl = bodyEl.dom.firstChild;
3173 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3174 textboxEl.enableDisplayMode();
3175 textboxEl.addKeyListener([10,13], function(){
3176 if(dlg.isVisible() && opt && opt.buttons){
3179 }else if(opt.buttons.yes){
3180 handleButton("yes");
3184 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3185 textareaEl.enableDisplayMode();
3186 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3187 progressEl.enableDisplayMode();
3189 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3190 var pf = progressEl.dom.firstChild;
3192 pp = Roo.get(pf.firstChild);
3193 pp.setHeight(pf.offsetHeight);
3201 * Updates the message box body text
3202 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3203 * the XHTML-compliant non-breaking space character '&#160;')
3204 * @return {Roo.MessageBox} This message box
3206 updateText : function(text)
3208 if(!dlg.isVisible() && !opt.width){
3209 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3210 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3212 msgEl.innerHTML = text || ' ';
3214 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3215 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3217 Math.min(opt.width || cw , this.maxWidth),
3218 Math.max(opt.minWidth || this.minWidth, bwidth)
3221 activeTextEl.setWidth(w);
3223 if(dlg.isVisible()){
3224 dlg.fixedcenter = false;
3226 // to big, make it scroll. = But as usual stupid IE does not support
3229 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3230 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3231 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3233 bodyEl.dom.style.height = '';
3234 bodyEl.dom.style.overflowY = '';
3237 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3239 bodyEl.dom.style.overflowX = '';
3242 dlg.setContentSize(w, bodyEl.getHeight());
3243 if(dlg.isVisible()){
3244 dlg.fixedcenter = true;
3250 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3251 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3252 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3253 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3254 * @return {Roo.MessageBox} This message box
3256 updateProgress : function(value, text){
3258 this.updateText(text);
3261 if (pp) { // weird bug on my firefox - for some reason this is not defined
3262 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3263 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3269 * Returns true if the message box is currently displayed
3270 * @return {Boolean} True if the message box is visible, else false
3272 isVisible : function(){
3273 return dlg && dlg.isVisible();
3277 * Hides the message box if it is displayed
3280 if(this.isVisible()){
3286 * Displays a new message box, or reinitializes an existing message box, based on the config options
3287 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3288 * The following config object properties are supported:
3290 Property Type Description
3291 ---------- --------------- ------------------------------------------------------------------------------------
3292 animEl String/Element An id or Element from which the message box should animate as it opens and
3293 closes (defaults to undefined)
3294 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3295 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3296 closable Boolean False to hide the top-right close button (defaults to true). Note that
3297 progress and wait dialogs will ignore this property and always hide the
3298 close button as they can only be closed programmatically.
3299 cls String A custom CSS class to apply to the message box element
3300 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3301 displayed (defaults to 75)
3302 fn Function A callback function to execute after closing the dialog. The arguments to the
3303 function will be btn (the name of the button that was clicked, if applicable,
3304 e.g. "ok"), and text (the value of the active text field, if applicable).
3305 Progress and wait dialogs will ignore this option since they do not respond to
3306 user actions and can only be closed programmatically, so any required function
3307 should be called by the same code after it closes the dialog.
3308 icon String A CSS class that provides a background image to be used as an icon for
3309 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3310 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3311 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3312 modal Boolean False to allow user interaction with the page while the message box is
3313 displayed (defaults to true)
3314 msg String A string that will replace the existing message box body text (defaults
3315 to the XHTML-compliant non-breaking space character ' ')
3316 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3317 progress Boolean True to display a progress bar (defaults to false)
3318 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3319 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3320 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3321 title String The title text
3322 value String The string value to set into the active textbox element if displayed
3323 wait Boolean True to display a progress bar (defaults to false)
3324 width Number The width of the dialog in pixels
3331 msg: 'Please enter your address:',
3333 buttons: Roo.MessageBox.OKCANCEL,
3336 animEl: 'addAddressBtn'
3339 * @param {Object} config Configuration options
3340 * @return {Roo.MessageBox} This message box
3342 show : function(options)
3345 // this causes nightmares if you show one dialog after another
3346 // especially on callbacks..
3348 if(this.isVisible()){
3351 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3352 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3353 Roo.log("New Dialog Message:" + options.msg )
3354 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3355 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3358 var d = this.getDialog();
3360 d.setTitle(opt.title || " ");
3361 d.closeEl.setDisplayed(opt.closable !== false);
3362 activeTextEl = textboxEl;
3363 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3368 textareaEl.setHeight(typeof opt.multiline == "number" ?
3369 opt.multiline : this.defaultTextHeight);
3370 activeTextEl = textareaEl;
3379 progressEl.setDisplayed(opt.progress === true);
3380 this.updateProgress(0);
3381 activeTextEl.dom.value = opt.value || "";
3383 dlg.setDefaultButton(activeTextEl);
3385 var bs = opt.buttons;
3389 }else if(bs && bs.yes){
3390 db = buttons["yes"];
3392 dlg.setDefaultButton(db);
3394 bwidth = updateButtons(opt.buttons);
3395 this.updateText(opt.msg);
3397 d.el.addClass(opt.cls);
3399 d.proxyDrag = opt.proxyDrag === true;
3400 d.modal = opt.modal !== false;
3401 d.mask = opt.modal !== false ? mask : false;
3403 // force it to the end of the z-index stack so it gets a cursor in FF
3404 document.body.appendChild(dlg.el.dom);
3405 d.animateTarget = null;
3406 d.show(options.animEl);
3412 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3413 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3414 * and closing the message box when the process is complete.
3415 * @param {String} title The title bar text
3416 * @param {String} msg The message box body text
3417 * @return {Roo.MessageBox} This message box
3419 progress : function(title, msg){
3426 minWidth: this.minProgressWidth,
3433 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3434 * If a callback function is passed it will be called after the user clicks the button, and the
3435 * id of the button that was clicked will be passed as the only parameter to the callback
3436 * (could also be the top-right close button).
3437 * @param {String} title The title bar text
3438 * @param {String} msg The message box body text
3439 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3440 * @param {Object} scope (optional) The scope of the callback function
3441 * @return {Roo.MessageBox} This message box
3443 alert : function(title, msg, fn, scope)
3458 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3459 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3460 * You are responsible for closing the message box when the process is complete.
3461 * @param {String} msg The message box body text
3462 * @param {String} title (optional) The title bar text
3463 * @return {Roo.MessageBox} This message box
3465 wait : function(msg, title){
3476 waitTimer = Roo.TaskMgr.start({
3478 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3486 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3487 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3488 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3489 * @param {String} title The title bar text
3490 * @param {String} msg The message box body text
3491 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3492 * @param {Object} scope (optional) The scope of the callback function
3493 * @return {Roo.MessageBox} This message box
3495 confirm : function(title, msg, fn, scope){
3499 buttons: this.YESNO,
3508 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3509 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3510 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3511 * (could also be the top-right close button) and the text that was entered will be passed as the two
3512 * parameters to the callback.
3513 * @param {String} title The title bar text
3514 * @param {String} msg The message box body text
3515 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3516 * @param {Object} scope (optional) The scope of the callback function
3517 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3518 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3519 * @return {Roo.MessageBox} This message box
3521 prompt : function(title, msg, fn, scope, multiline){
3525 buttons: this.OKCANCEL,
3530 multiline: multiline,
3537 * Button config that displays a single OK button
3542 * Button config that displays Yes and No buttons
3545 YESNO : {yes:true, no:true},
3547 * Button config that displays OK and Cancel buttons
3550 OKCANCEL : {ok:true, cancel:true},
3552 * Button config that displays Yes, No and Cancel buttons
3555 YESNOCANCEL : {yes:true, no:true, cancel:true},
3558 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3561 defaultTextHeight : 75,
3563 * The maximum width in pixels of the message box (defaults to 600)
3568 * The minimum width in pixels of the message box (defaults to 100)
3573 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3574 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3577 minProgressWidth : 250,
3579 * An object containing the default button text strings that can be overriden for localized language support.
3580 * Supported properties are: ok, cancel, yes and no.
3581 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3594 * Shorthand for {@link Roo.MessageBox}
3596 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3597 Roo.Msg = Roo.Msg || Roo.MessageBox;
3606 * @class Roo.bootstrap.Navbar
3607 * @extends Roo.bootstrap.Component
3608 * Bootstrap Navbar class
3611 * Create a new Navbar
3612 * @param {Object} config The config object
3616 Roo.bootstrap.Navbar = function(config){
3617 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3621 * @event beforetoggle
3622 * Fire before toggle the menu
3623 * @param {Roo.EventObject} e
3625 "beforetoggle" : true
3629 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3638 getAutoCreate : function(){
3641 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3645 initEvents :function ()
3647 //Roo.log(this.el.select('.navbar-toggle',true));
3648 this.el.select('.navbar-toggle',true).on('click', function() {
3649 if(this.fireEvent('beforetoggle', this) !== false){
3650 this.el.select('.navbar-collapse',true).toggleClass('in');
3660 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3662 var size = this.el.getSize();
3663 this.maskEl.setSize(size.width, size.height);
3664 this.maskEl.enableDisplayMode("block");
3673 getChildContainer : function()
3675 if (this.el.select('.collapse').getCount()) {
3676 return this.el.select('.collapse',true).first();
3709 * @class Roo.bootstrap.NavSimplebar
3710 * @extends Roo.bootstrap.Navbar
3711 * Bootstrap Sidebar class
3713 * @cfg {Boolean} inverse is inverted color
3715 * @cfg {String} type (nav | pills | tabs)
3716 * @cfg {Boolean} arrangement stacked | justified
3717 * @cfg {String} align (left | right) alignment
3719 * @cfg {Boolean} main (true|false) main nav bar? default false
3720 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3722 * @cfg {String} tag (header|footer|nav|div) default is nav
3728 * Create a new Sidebar
3729 * @param {Object} config The config object
3733 Roo.bootstrap.NavSimplebar = function(config){
3734 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3737 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3753 getAutoCreate : function(){
3757 tag : this.tag || 'div',
3770 this.type = this.type || 'nav';
3771 if (['tabs','pills'].indexOf(this.type)!==-1) {
3772 cfg.cn[0].cls += ' nav-' + this.type
3776 if (this.type!=='nav') {
3777 Roo.log('nav type must be nav/tabs/pills')
3779 cfg.cn[0].cls += ' navbar-nav'
3785 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3786 cfg.cn[0].cls += ' nav-' + this.arrangement;
3790 if (this.align === 'right') {
3791 cfg.cn[0].cls += ' navbar-right';
3795 cfg.cls += ' navbar-inverse';
3822 * @class Roo.bootstrap.NavHeaderbar
3823 * @extends Roo.bootstrap.NavSimplebar
3824 * Bootstrap Sidebar class
3826 * @cfg {String} brand what is brand
3827 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3828 * @cfg {String} brand_href href of the brand
3829 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3830 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3831 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3832 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3835 * Create a new Sidebar
3836 * @param {Object} config The config object
3840 Roo.bootstrap.NavHeaderbar = function(config){
3841 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3845 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3852 desktopCenter : false,
3855 getAutoCreate : function(){
3858 tag: this.nav || 'nav',
3865 if (this.desktopCenter) {
3866 cn.push({cls : 'container', cn : []});
3873 cls: 'navbar-header',
3878 cls: 'navbar-toggle',
3879 'data-toggle': 'collapse',
3884 html: 'Toggle navigation'
3906 cls: 'collapse navbar-collapse',
3910 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3912 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3913 cfg.cls += ' navbar-' + this.position;
3915 // tag can override this..
3917 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3920 if (this.brand !== '') {
3923 href: this.brand_href ? this.brand_href : '#',
3924 cls: 'navbar-brand',
3932 cfg.cls += ' main-nav';
3940 getHeaderChildContainer : function()
3942 if (this.srButton && this.el.select('.navbar-header').getCount()) {
3943 return this.el.select('.navbar-header',true).first();
3946 return this.getChildContainer();
3950 initEvents : function()
3952 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3954 if (this.autohide) {
3959 Roo.get(document).on('scroll',function(e) {
3960 var ns = Roo.get(document).getScroll().top;
3961 var os = prevScroll;
3965 ft.removeClass('slideDown');
3966 ft.addClass('slideUp');
3969 ft.removeClass('slideUp');
3970 ft.addClass('slideDown');
3991 * @class Roo.bootstrap.NavSidebar
3992 * @extends Roo.bootstrap.Navbar
3993 * Bootstrap Sidebar class
3996 * Create a new Sidebar
3997 * @param {Object} config The config object
4001 Roo.bootstrap.NavSidebar = function(config){
4002 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4005 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4007 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4009 getAutoCreate : function(){
4014 cls: 'sidebar sidebar-nav'
4036 * @class Roo.bootstrap.NavGroup
4037 * @extends Roo.bootstrap.Component
4038 * Bootstrap NavGroup class
4039 * @cfg {String} align (left|right)
4040 * @cfg {Boolean} inverse
4041 * @cfg {String} type (nav|pills|tab) default nav
4042 * @cfg {String} navId - reference Id for navbar.
4046 * Create a new nav group
4047 * @param {Object} config The config object
4050 Roo.bootstrap.NavGroup = function(config){
4051 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4054 Roo.bootstrap.NavGroup.register(this);
4058 * Fires when the active item changes
4059 * @param {Roo.bootstrap.NavGroup} this
4060 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4061 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4068 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4079 getAutoCreate : function()
4081 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4088 if (['tabs','pills'].indexOf(this.type)!==-1) {
4089 cfg.cls += ' nav-' + this.type
4091 if (this.type!=='nav') {
4092 Roo.log('nav type must be nav/tabs/pills')
4094 cfg.cls += ' navbar-nav'
4097 if (this.parent() && this.parent().sidebar) {
4100 cls: 'dashboard-menu sidebar-menu'
4106 if (this.form === true) {
4112 if (this.align === 'right') {
4113 cfg.cls += ' navbar-right';
4115 cfg.cls += ' navbar-left';
4119 if (this.align === 'right') {
4120 cfg.cls += ' navbar-right';
4124 cfg.cls += ' navbar-inverse';
4132 * sets the active Navigation item
4133 * @param {Roo.bootstrap.NavItem} the new current navitem
4135 setActiveItem : function(item)
4138 Roo.each(this.navItems, function(v){
4143 v.setActive(false, true);
4150 item.setActive(true, true);
4151 this.fireEvent('changed', this, item, prev);
4156 * gets the active Navigation item
4157 * @return {Roo.bootstrap.NavItem} the current navitem
4159 getActive : function()
4163 Roo.each(this.navItems, function(v){
4174 indexOfNav : function()
4178 Roo.each(this.navItems, function(v,i){
4189 * adds a Navigation item
4190 * @param {Roo.bootstrap.NavItem} the navitem to add
4192 addItem : function(cfg)
4194 var cn = new Roo.bootstrap.NavItem(cfg);
4196 cn.parentId = this.id;
4197 cn.onRender(this.el, null);
4201 * register a Navigation item
4202 * @param {Roo.bootstrap.NavItem} the navitem to add
4204 register : function(item)
4206 this.navItems.push( item);
4207 item.navId = this.navId;
4212 * clear all the Navigation item
4215 clearAll : function()
4218 this.el.dom.innerHTML = '';
4221 getNavItem: function(tabId)
4224 Roo.each(this.navItems, function(e) {
4225 if (e.tabId == tabId) {
4235 setActiveNext : function()
4237 var i = this.indexOfNav(this.getActive());
4238 if (i > this.navItems.length) {
4241 this.setActiveItem(this.navItems[i+1]);
4243 setActivePrev : function()
4245 var i = this.indexOfNav(this.getActive());
4249 this.setActiveItem(this.navItems[i-1]);
4251 clearWasActive : function(except) {
4252 Roo.each(this.navItems, function(e) {
4253 if (e.tabId != except.tabId && e.was_active) {
4254 e.was_active = false;
4261 getWasActive : function ()
4264 Roo.each(this.navItems, function(e) {
4279 Roo.apply(Roo.bootstrap.NavGroup, {
4283 * register a Navigation Group
4284 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4286 register : function(navgrp)
4288 this.groups[navgrp.navId] = navgrp;
4292 * fetch a Navigation Group based on the navigation ID
4293 * @param {string} the navgroup to add
4294 * @returns {Roo.bootstrap.NavGroup} the navgroup
4296 get: function(navId) {
4297 if (typeof(this.groups[navId]) == 'undefined') {
4299 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4301 return this.groups[navId] ;
4316 * @class Roo.bootstrap.NavItem
4317 * @extends Roo.bootstrap.Component
4318 * Bootstrap Navbar.NavItem class
4319 * @cfg {String} href link to
4320 * @cfg {String} html content of button
4321 * @cfg {String} badge text inside badge
4322 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4323 * @cfg {String} glyphicon name of glyphicon
4324 * @cfg {String} icon name of font awesome icon
4325 * @cfg {Boolean} active Is item active
4326 * @cfg {Boolean} disabled Is item disabled
4328 * @cfg {Boolean} preventDefault (true | false) default false
4329 * @cfg {String} tabId the tab that this item activates.
4330 * @cfg {String} tagtype (a|span) render as a href or span?
4331 * @cfg {Boolean} animateRef (true|false) link to element default false
4334 * Create a new Navbar Item
4335 * @param {Object} config The config object
4337 Roo.bootstrap.NavItem = function(config){
4338 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4343 * The raw click event for the entire grid.
4344 * @param {Roo.EventObject} e
4349 * Fires when the active item active state changes
4350 * @param {Roo.bootstrap.NavItem} this
4351 * @param {boolean} state the new state
4357 * Fires when scroll to element
4358 * @param {Roo.bootstrap.NavItem} this
4359 * @param {Object} options
4360 * @param {Roo.EventObject} e
4368 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4376 preventDefault : false,
4383 getAutoCreate : function(){
4392 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4394 if (this.disabled) {
4395 cfg.cls += ' disabled';
4398 if (this.href || this.html || this.glyphicon || this.icon) {
4402 href : this.href || "#",
4403 html: this.html || ''
4408 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4411 if(this.glyphicon) {
4412 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4417 cfg.cn[0].html += " <span class='caret'></span>";
4421 if (this.badge !== '') {
4423 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4431 initEvents: function()
4433 if (typeof (this.menu) != 'undefined') {
4434 this.menu.parentType = this.xtype;
4435 this.menu.triggerEl = this.el;
4436 this.menu = this.addxtype(Roo.apply({}, this.menu));
4439 this.el.select('a',true).on('click', this.onClick, this);
4441 if(this.tagtype == 'span'){
4442 this.el.select('span',true).on('click', this.onClick, this);
4445 // at this point parent should be available..
4446 this.parent().register(this);
4449 onClick : function(e)
4451 if (e.getTarget('.dropdown-menu-item')) {
4452 // did you click on a menu itemm.... - then don't trigger onclick..
4457 this.preventDefault ||
4460 Roo.log("NavItem - prevent Default?");
4464 if (this.disabled) {
4468 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4469 if (tg && tg.transition) {
4470 Roo.log("waiting for the transitionend");
4476 //Roo.log("fire event clicked");
4477 if(this.fireEvent('click', this, e) === false){
4481 if(this.tagtype == 'span'){
4485 //Roo.log(this.href);
4486 var ael = this.el.select('a',true).first();
4489 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4490 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4491 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4492 return; // ignore... - it's a 'hash' to another page.
4494 Roo.log("NavItem - prevent Default?");
4496 this.scrollToElement(e);
4500 var p = this.parent();
4502 if (['tabs','pills'].indexOf(p.type)!==-1) {
4503 if (typeof(p.setActiveItem) !== 'undefined') {
4504 p.setActiveItem(this);
4508 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4509 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4510 // remove the collapsed menu expand...
4511 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4515 isActive: function () {
4518 setActive : function(state, fire, is_was_active)
4520 if (this.active && !state && this.navId) {
4521 this.was_active = true;
4522 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4524 nv.clearWasActive(this);
4528 this.active = state;
4531 this.el.removeClass('active');
4532 } else if (!this.el.hasClass('active')) {
4533 this.el.addClass('active');
4536 this.fireEvent('changed', this, state);
4539 // show a panel if it's registered and related..
4541 if (!this.navId || !this.tabId || !state || is_was_active) {
4545 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4549 var pan = tg.getPanelByName(this.tabId);
4553 // if we can not flip to new panel - go back to old nav highlight..
4554 if (false == tg.showPanel(pan)) {
4555 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4557 var onav = nv.getWasActive();
4559 onav.setActive(true, false, true);
4568 // this should not be here...
4569 setDisabled : function(state)
4571 this.disabled = state;
4573 this.el.removeClass('disabled');
4574 } else if (!this.el.hasClass('disabled')) {
4575 this.el.addClass('disabled');
4581 * Fetch the element to display the tooltip on.
4582 * @return {Roo.Element} defaults to this.el
4584 tooltipEl : function()
4586 return this.el.select('' + this.tagtype + '', true).first();
4589 scrollToElement : function(e)
4591 var c = document.body;
4594 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4596 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4597 c = document.documentElement;
4600 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4606 var o = target.calcOffsetsTo(c);
4613 this.fireEvent('scrollto', this, options, e);
4615 Roo.get(c).scrollTo('top', options.value, true);
4628 * <span> icon </span>
4629 * <span> text </span>
4630 * <span>badge </span>
4634 * @class Roo.bootstrap.NavSidebarItem
4635 * @extends Roo.bootstrap.NavItem
4636 * Bootstrap Navbar.NavSidebarItem class
4637 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4638 * {Boolean} open is the menu open
4639 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4640 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4641 * {String} buttonSize (sm|md|lg)the extra classes for the button
4642 * {Boolean} showArrow show arrow next to the text (default true)
4644 * Create a new Navbar Button
4645 * @param {Object} config The config object
4647 Roo.bootstrap.NavSidebarItem = function(config){
4648 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4653 * The raw click event for the entire grid.
4654 * @param {Roo.EventObject} e
4659 * Fires when the active item active state changes
4660 * @param {Roo.bootstrap.NavSidebarItem} this
4661 * @param {boolean} state the new state
4669 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4671 badgeWeight : 'default',
4677 buttonWeight : 'default',
4683 getAutoCreate : function(){
4688 href : this.href || '#',
4694 if(this.buttonView){
4697 href : this.href || '#',
4698 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4711 cfg.cls += ' active';
4714 if (this.disabled) {
4715 cfg.cls += ' disabled';
4718 cfg.cls += ' open x-open';
4721 if (this.glyphicon || this.icon) {
4722 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4723 a.cn.push({ tag : 'i', cls : c }) ;
4726 if(!this.buttonView){
4729 html : this.html || ''
4736 if (this.badge !== '') {
4737 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4743 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4746 a.cls += ' dropdown-toggle treeview' ;
4752 initEvents : function()
4754 if (typeof (this.menu) != 'undefined') {
4755 this.menu.parentType = this.xtype;
4756 this.menu.triggerEl = this.el;
4757 this.menu = this.addxtype(Roo.apply({}, this.menu));
4760 this.el.on('click', this.onClick, this);
4762 if(this.badge !== ''){
4763 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4768 onClick : function(e)
4775 if(this.preventDefault){
4779 this.fireEvent('click', this);
4782 disable : function()
4784 this.setDisabled(true);
4789 this.setDisabled(false);
4792 setDisabled : function(state)
4794 if(this.disabled == state){
4798 this.disabled = state;
4801 this.el.addClass('disabled');
4805 this.el.removeClass('disabled');
4810 setActive : function(state)
4812 if(this.active == state){
4816 this.active = state;
4819 this.el.addClass('active');
4823 this.el.removeClass('active');
4828 isActive: function ()
4833 setBadge : function(str)
4839 this.badgeEl.dom.innerHTML = str;
4856 * @class Roo.bootstrap.Row
4857 * @extends Roo.bootstrap.Component
4858 * Bootstrap Row class (contains columns...)
4862 * @param {Object} config The config object
4865 Roo.bootstrap.Row = function(config){
4866 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4869 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4871 getAutoCreate : function(){
4890 * @class Roo.bootstrap.Element
4891 * @extends Roo.bootstrap.Component
4892 * Bootstrap Element class
4893 * @cfg {String} html contents of the element
4894 * @cfg {String} tag tag of the element
4895 * @cfg {String} cls class of the element
4896 * @cfg {Boolean} preventDefault (true|false) default false
4897 * @cfg {Boolean} clickable (true|false) default false
4900 * Create a new Element
4901 * @param {Object} config The config object
4904 Roo.bootstrap.Element = function(config){
4905 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4911 * When a element is chick
4912 * @param {Roo.bootstrap.Element} this
4913 * @param {Roo.EventObject} e
4919 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4924 preventDefault: false,
4927 getAutoCreate : function(){
4931 // cls: this.cls, double assign in parent class Component.js :: onRender
4938 initEvents: function()
4940 Roo.bootstrap.Element.superclass.initEvents.call(this);
4943 this.el.on('click', this.onClick, this);
4948 onClick : function(e)
4950 if(this.preventDefault){
4954 this.fireEvent('click', this, e);
4957 getValue : function()
4959 return this.el.dom.innerHTML;
4962 setValue : function(value)
4964 this.el.dom.innerHTML = value;
4979 * @class Roo.bootstrap.Pagination
4980 * @extends Roo.bootstrap.Component
4981 * Bootstrap Pagination class
4982 * @cfg {String} size xs | sm | md | lg
4983 * @cfg {Boolean} inverse false | true
4986 * Create a new Pagination
4987 * @param {Object} config The config object
4990 Roo.bootstrap.Pagination = function(config){
4991 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4994 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5000 getAutoCreate : function(){
5006 cfg.cls += ' inverse';
5012 cfg.cls += " " + this.cls;
5030 * @class Roo.bootstrap.PaginationItem
5031 * @extends Roo.bootstrap.Component
5032 * Bootstrap PaginationItem class
5033 * @cfg {String} html text
5034 * @cfg {String} href the link
5035 * @cfg {Boolean} preventDefault (true | false) default true
5036 * @cfg {Boolean} active (true | false) default false
5037 * @cfg {Boolean} disabled default false
5041 * Create a new PaginationItem
5042 * @param {Object} config The config object
5046 Roo.bootstrap.PaginationItem = function(config){
5047 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5052 * The raw click event for the entire grid.
5053 * @param {Roo.EventObject} e
5059 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5063 preventDefault: true,
5068 getAutoCreate : function(){
5074 href : this.href ? this.href : '#',
5075 html : this.html ? this.html : ''
5085 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5089 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5095 initEvents: function() {
5097 this.el.on('click', this.onClick, this);
5100 onClick : function(e)
5102 Roo.log('PaginationItem on click ');
5103 if(this.preventDefault){
5111 this.fireEvent('click', this, e);
5127 * @class Roo.bootstrap.Slider
5128 * @extends Roo.bootstrap.Component
5129 * Bootstrap Slider class
5132 * Create a new Slider
5133 * @param {Object} config The config object
5136 Roo.bootstrap.Slider = function(config){
5137 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5140 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5142 getAutoCreate : function(){
5146 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5150 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5162 * Ext JS Library 1.1.1
5163 * Copyright(c) 2006-2007, Ext JS, LLC.
5165 * Originally Released Under LGPL - original licence link has changed is not relivant.
5168 * <script type="text/javascript">
5173 * @class Roo.grid.ColumnModel
5174 * @extends Roo.util.Observable
5175 * This is the default implementation of a ColumnModel used by the Grid. It defines
5176 * the columns in the grid.
5179 var colModel = new Roo.grid.ColumnModel([
5180 {header: "Ticker", width: 60, sortable: true, locked: true},
5181 {header: "Company Name", width: 150, sortable: true},
5182 {header: "Market Cap.", width: 100, sortable: true},
5183 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5184 {header: "Employees", width: 100, sortable: true, resizable: false}
5189 * The config options listed for this class are options which may appear in each
5190 * individual column definition.
5191 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5193 * @param {Object} config An Array of column config objects. See this class's
5194 * config objects for details.
5196 Roo.grid.ColumnModel = function(config){
5198 * The config passed into the constructor
5200 this.config = config;
5203 // if no id, create one
5204 // if the column does not have a dataIndex mapping,
5205 // map it to the order it is in the config
5206 for(var i = 0, len = config.length; i < len; i++){
5208 if(typeof c.dataIndex == "undefined"){
5211 if(typeof c.renderer == "string"){
5212 c.renderer = Roo.util.Format[c.renderer];
5214 if(typeof c.id == "undefined"){
5217 if(c.editor && c.editor.xtype){
5218 c.editor = Roo.factory(c.editor, Roo.grid);
5220 if(c.editor && c.editor.isFormField){
5221 c.editor = new Roo.grid.GridEditor(c.editor);
5223 this.lookup[c.id] = c;
5227 * The width of columns which have no width specified (defaults to 100)
5230 this.defaultWidth = 100;
5233 * Default sortable of columns which have no sortable specified (defaults to false)
5236 this.defaultSortable = false;
5240 * @event widthchange
5241 * Fires when the width of a column changes.
5242 * @param {ColumnModel} this
5243 * @param {Number} columnIndex The column index
5244 * @param {Number} newWidth The new width
5246 "widthchange": true,
5248 * @event headerchange
5249 * Fires when the text of a header changes.
5250 * @param {ColumnModel} this
5251 * @param {Number} columnIndex The column index
5252 * @param {Number} newText The new header text
5254 "headerchange": true,
5256 * @event hiddenchange
5257 * Fires when a column is hidden or "unhidden".
5258 * @param {ColumnModel} this
5259 * @param {Number} columnIndex The column index
5260 * @param {Boolean} hidden true if hidden, false otherwise
5262 "hiddenchange": true,
5264 * @event columnmoved
5265 * Fires when a column is moved.
5266 * @param {ColumnModel} this
5267 * @param {Number} oldIndex
5268 * @param {Number} newIndex
5270 "columnmoved" : true,
5272 * @event columlockchange
5273 * Fires when a column's locked state is changed
5274 * @param {ColumnModel} this
5275 * @param {Number} colIndex
5276 * @param {Boolean} locked true if locked
5278 "columnlockchange" : true
5280 Roo.grid.ColumnModel.superclass.constructor.call(this);
5282 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5284 * @cfg {String} header The header text to display in the Grid view.
5287 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5288 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5289 * specified, the column's index is used as an index into the Record's data Array.
5292 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5293 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5296 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5297 * Defaults to the value of the {@link #defaultSortable} property.
5298 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5301 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5304 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5307 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5310 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5313 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5314 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5315 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5316 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5319 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5322 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5325 * @cfg {String} cursor (Optional)
5328 * @cfg {String} tooltip (Optional)
5331 * @cfg {Number} xs (Optional)
5334 * @cfg {Number} sm (Optional)
5337 * @cfg {Number} md (Optional)
5340 * @cfg {Number} lg (Optional)
5343 * Returns the id of the column at the specified index.
5344 * @param {Number} index The column index
5345 * @return {String} the id
5347 getColumnId : function(index){
5348 return this.config[index].id;
5352 * Returns the column for a specified id.
5353 * @param {String} id The column id
5354 * @return {Object} the column
5356 getColumnById : function(id){
5357 return this.lookup[id];
5362 * Returns the column for a specified dataIndex.
5363 * @param {String} dataIndex The column dataIndex
5364 * @return {Object|Boolean} the column or false if not found
5366 getColumnByDataIndex: function(dataIndex){
5367 var index = this.findColumnIndex(dataIndex);
5368 return index > -1 ? this.config[index] : false;
5372 * Returns the index for a specified column id.
5373 * @param {String} id The column id
5374 * @return {Number} the index, or -1 if not found
5376 getIndexById : function(id){
5377 for(var i = 0, len = this.config.length; i < len; i++){
5378 if(this.config[i].id == id){
5386 * Returns the index for a specified column dataIndex.
5387 * @param {String} dataIndex The column dataIndex
5388 * @return {Number} the index, or -1 if not found
5391 findColumnIndex : function(dataIndex){
5392 for(var i = 0, len = this.config.length; i < len; i++){
5393 if(this.config[i].dataIndex == dataIndex){
5401 moveColumn : function(oldIndex, newIndex){
5402 var c = this.config[oldIndex];
5403 this.config.splice(oldIndex, 1);
5404 this.config.splice(newIndex, 0, c);
5405 this.dataMap = null;
5406 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5409 isLocked : function(colIndex){
5410 return this.config[colIndex].locked === true;
5413 setLocked : function(colIndex, value, suppressEvent){
5414 if(this.isLocked(colIndex) == value){
5417 this.config[colIndex].locked = value;
5419 this.fireEvent("columnlockchange", this, colIndex, value);
5423 getTotalLockedWidth : function(){
5425 for(var i = 0; i < this.config.length; i++){
5426 if(this.isLocked(i) && !this.isHidden(i)){
5427 this.totalWidth += this.getColumnWidth(i);
5433 getLockedCount : function(){
5434 for(var i = 0, len = this.config.length; i < len; i++){
5435 if(!this.isLocked(i)){
5440 return this.config.length;
5444 * Returns the number of columns.
5447 getColumnCount : function(visibleOnly){
5448 if(visibleOnly === true){
5450 for(var i = 0, len = this.config.length; i < len; i++){
5451 if(!this.isHidden(i)){
5457 return this.config.length;
5461 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5462 * @param {Function} fn
5463 * @param {Object} scope (optional)
5464 * @return {Array} result
5466 getColumnsBy : function(fn, scope){
5468 for(var i = 0, len = this.config.length; i < len; i++){
5469 var c = this.config[i];
5470 if(fn.call(scope||this, c, i) === true){
5478 * Returns true if the specified column is sortable.
5479 * @param {Number} col The column index
5482 isSortable : function(col){
5483 if(typeof this.config[col].sortable == "undefined"){
5484 return this.defaultSortable;
5486 return this.config[col].sortable;
5490 * Returns the rendering (formatting) function defined for the column.
5491 * @param {Number} col The column index.
5492 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5494 getRenderer : function(col){
5495 if(!this.config[col].renderer){
5496 return Roo.grid.ColumnModel.defaultRenderer;
5498 return this.config[col].renderer;
5502 * Sets the rendering (formatting) function for a column.
5503 * @param {Number} col The column index
5504 * @param {Function} fn The function to use to process the cell's raw data
5505 * to return HTML markup for the grid view. The render function is called with
5506 * the following parameters:<ul>
5507 * <li>Data value.</li>
5508 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5509 * <li>css A CSS style string to apply to the table cell.</li>
5510 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5511 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5512 * <li>Row index</li>
5513 * <li>Column index</li>
5514 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5516 setRenderer : function(col, fn){
5517 this.config[col].renderer = fn;
5521 * Returns the width for the specified column.
5522 * @param {Number} col The column index
5525 getColumnWidth : function(col){
5526 return this.config[col].width * 1 || this.defaultWidth;
5530 * Sets the width for a column.
5531 * @param {Number} col The column index
5532 * @param {Number} width The new width
5534 setColumnWidth : function(col, width, suppressEvent){
5535 this.config[col].width = width;
5536 this.totalWidth = null;
5538 this.fireEvent("widthchange", this, col, width);
5543 * Returns the total width of all columns.
5544 * @param {Boolean} includeHidden True to include hidden column widths
5547 getTotalWidth : function(includeHidden){
5548 if(!this.totalWidth){
5549 this.totalWidth = 0;
5550 for(var i = 0, len = this.config.length; i < len; i++){
5551 if(includeHidden || !this.isHidden(i)){
5552 this.totalWidth += this.getColumnWidth(i);
5556 return this.totalWidth;
5560 * Returns the header for the specified column.
5561 * @param {Number} col The column index
5564 getColumnHeader : function(col){
5565 return this.config[col].header;
5569 * Sets the header for a column.
5570 * @param {Number} col The column index
5571 * @param {String} header The new header
5573 setColumnHeader : function(col, header){
5574 this.config[col].header = header;
5575 this.fireEvent("headerchange", this, col, header);
5579 * Returns the tooltip for the specified column.
5580 * @param {Number} col The column index
5583 getColumnTooltip : function(col){
5584 return this.config[col].tooltip;
5587 * Sets the tooltip for a column.
5588 * @param {Number} col The column index
5589 * @param {String} tooltip The new tooltip
5591 setColumnTooltip : function(col, tooltip){
5592 this.config[col].tooltip = tooltip;
5596 * Returns the dataIndex for the specified column.
5597 * @param {Number} col The column index
5600 getDataIndex : function(col){
5601 return this.config[col].dataIndex;
5605 * Sets the dataIndex for a column.
5606 * @param {Number} col The column index
5607 * @param {Number} dataIndex The new dataIndex
5609 setDataIndex : function(col, dataIndex){
5610 this.config[col].dataIndex = dataIndex;
5616 * Returns true if the cell is editable.
5617 * @param {Number} colIndex The column index
5618 * @param {Number} rowIndex The row index - this is nto actually used..?
5621 isCellEditable : function(colIndex, rowIndex){
5622 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5626 * Returns the editor defined for the cell/column.
5627 * return false or null to disable editing.
5628 * @param {Number} colIndex The column index
5629 * @param {Number} rowIndex The row index
5632 getCellEditor : function(colIndex, rowIndex){
5633 return this.config[colIndex].editor;
5637 * Sets if a column is editable.
5638 * @param {Number} col The column index
5639 * @param {Boolean} editable True if the column is editable
5641 setEditable : function(col, editable){
5642 this.config[col].editable = editable;
5647 * Returns true if the column is hidden.
5648 * @param {Number} colIndex The column index
5651 isHidden : function(colIndex){
5652 return this.config[colIndex].hidden;
5657 * Returns true if the column width cannot be changed
5659 isFixed : function(colIndex){
5660 return this.config[colIndex].fixed;
5664 * Returns true if the column can be resized
5667 isResizable : function(colIndex){
5668 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5671 * Sets if a column is hidden.
5672 * @param {Number} colIndex The column index
5673 * @param {Boolean} hidden True if the column is hidden
5675 setHidden : function(colIndex, hidden){
5676 this.config[colIndex].hidden = hidden;
5677 this.totalWidth = null;
5678 this.fireEvent("hiddenchange", this, colIndex, hidden);
5682 * Sets the editor for a column.
5683 * @param {Number} col The column index
5684 * @param {Object} editor The editor object
5686 setEditor : function(col, editor){
5687 this.config[col].editor = editor;
5691 Roo.grid.ColumnModel.defaultRenderer = function(value)
5693 if(typeof value == "object") {
5696 if(typeof value == "string" && value.length < 1){
5700 return String.format("{0}", value);
5703 // Alias for backwards compatibility
5704 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5707 * Ext JS Library 1.1.1
5708 * Copyright(c) 2006-2007, Ext JS, LLC.
5710 * Originally Released Under LGPL - original licence link has changed is not relivant.
5713 * <script type="text/javascript">
5717 * @class Roo.LoadMask
5718 * A simple utility class for generically masking elements while loading data. If the element being masked has
5719 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5720 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5721 * element's UpdateManager load indicator and will be destroyed after the initial load.
5723 * Create a new LoadMask
5724 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5725 * @param {Object} config The config object
5727 Roo.LoadMask = function(el, config){
5728 this.el = Roo.get(el);
5729 Roo.apply(this, config);
5731 this.store.on('beforeload', this.onBeforeLoad, this);
5732 this.store.on('load', this.onLoad, this);
5733 this.store.on('loadexception', this.onLoadException, this);
5734 this.removeMask = false;
5736 var um = this.el.getUpdateManager();
5737 um.showLoadIndicator = false; // disable the default indicator
5738 um.on('beforeupdate', this.onBeforeLoad, this);
5739 um.on('update', this.onLoad, this);
5740 um.on('failure', this.onLoad, this);
5741 this.removeMask = true;
5745 Roo.LoadMask.prototype = {
5747 * @cfg {Boolean} removeMask
5748 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5749 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5753 * The text to display in a centered loading message box (defaults to 'Loading...')
5757 * @cfg {String} msgCls
5758 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5760 msgCls : 'x-mask-loading',
5763 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5769 * Disables the mask to prevent it from being displayed
5771 disable : function(){
5772 this.disabled = true;
5776 * Enables the mask so that it can be displayed
5778 enable : function(){
5779 this.disabled = false;
5782 onLoadException : function()
5786 if (typeof(arguments[3]) != 'undefined') {
5787 Roo.MessageBox.alert("Error loading",arguments[3]);
5791 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5792 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5799 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5804 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5808 onBeforeLoad : function(){
5810 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5815 destroy : function(){
5817 this.store.un('beforeload', this.onBeforeLoad, this);
5818 this.store.un('load', this.onLoad, this);
5819 this.store.un('loadexception', this.onLoadException, this);
5821 var um = this.el.getUpdateManager();
5822 um.un('beforeupdate', this.onBeforeLoad, this);
5823 um.un('update', this.onLoad, this);
5824 um.un('failure', this.onLoad, this);
5835 * @class Roo.bootstrap.Table
5836 * @extends Roo.bootstrap.Component
5837 * Bootstrap Table class
5838 * @cfg {String} cls table class
5839 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5840 * @cfg {String} bgcolor Specifies the background color for a table
5841 * @cfg {Number} border Specifies whether the table cells should have borders or not
5842 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5843 * @cfg {Number} cellspacing Specifies the space between cells
5844 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5845 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5846 * @cfg {String} sortable Specifies that the table should be sortable
5847 * @cfg {String} summary Specifies a summary of the content of a table
5848 * @cfg {Number} width Specifies the width of a table
5849 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5851 * @cfg {boolean} striped Should the rows be alternative striped
5852 * @cfg {boolean} bordered Add borders to the table
5853 * @cfg {boolean} hover Add hover highlighting
5854 * @cfg {boolean} condensed Format condensed
5855 * @cfg {boolean} responsive Format condensed
5856 * @cfg {Boolean} loadMask (true|false) default false
5857 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5858 * @cfg {Boolean} headerShow (true|false) generate thead, default true
5859 * @cfg {Boolean} rowSelection (true|false) default false
5860 * @cfg {Boolean} cellSelection (true|false) default false
5861 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5862 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5863 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
5867 * Create a new Table
5868 * @param {Object} config The config object
5871 Roo.bootstrap.Table = function(config){
5872 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5877 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5878 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5879 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5880 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5882 this.sm = this.sm || {xtype: 'RowSelectionModel'};
5884 this.sm.grid = this;
5885 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5886 this.sm = this.selModel;
5887 this.sm.xmodule = this.xmodule || false;
5890 if (this.cm && typeof(this.cm.config) == 'undefined') {
5891 this.colModel = new Roo.grid.ColumnModel(this.cm);
5892 this.cm = this.colModel;
5893 this.cm.xmodule = this.xmodule || false;
5896 this.store= Roo.factory(this.store, Roo.data);
5897 this.ds = this.store;
5898 this.ds.xmodule = this.xmodule || false;
5901 if (this.footer && this.store) {
5902 this.footer.dataSource = this.ds;
5903 this.footer = Roo.factory(this.footer);
5910 * Fires when a cell is clicked
5911 * @param {Roo.bootstrap.Table} this
5912 * @param {Roo.Element} el
5913 * @param {Number} rowIndex
5914 * @param {Number} columnIndex
5915 * @param {Roo.EventObject} e
5919 * @event celldblclick
5920 * Fires when a cell is double clicked
5921 * @param {Roo.bootstrap.Table} this
5922 * @param {Roo.Element} el
5923 * @param {Number} rowIndex
5924 * @param {Number} columnIndex
5925 * @param {Roo.EventObject} e
5927 "celldblclick" : true,
5930 * Fires when a row is clicked
5931 * @param {Roo.bootstrap.Table} this
5932 * @param {Roo.Element} el
5933 * @param {Number} rowIndex
5934 * @param {Roo.EventObject} e
5938 * @event rowdblclick
5939 * Fires when a row is double clicked
5940 * @param {Roo.bootstrap.Table} this
5941 * @param {Roo.Element} el
5942 * @param {Number} rowIndex
5943 * @param {Roo.EventObject} e
5945 "rowdblclick" : true,
5948 * Fires when a mouseover occur
5949 * @param {Roo.bootstrap.Table} this
5950 * @param {Roo.Element} el
5951 * @param {Number} rowIndex
5952 * @param {Number} columnIndex
5953 * @param {Roo.EventObject} e
5958 * Fires when a mouseout occur
5959 * @param {Roo.bootstrap.Table} this
5960 * @param {Roo.Element} el
5961 * @param {Number} rowIndex
5962 * @param {Number} columnIndex
5963 * @param {Roo.EventObject} e
5968 * Fires when a row is rendered, so you can change add a style to it.
5969 * @param {Roo.bootstrap.Table} this
5970 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5974 * @event rowsrendered
5975 * Fires when all the rows have been rendered
5976 * @param {Roo.bootstrap.Table} this
5978 'rowsrendered' : true,
5980 * @event contextmenu
5981 * The raw contextmenu event for the entire grid.
5982 * @param {Roo.EventObject} e
5984 "contextmenu" : true,
5986 * @event rowcontextmenu
5987 * Fires when a row is right clicked
5988 * @param {Roo.bootstrap.Table} this
5989 * @param {Number} rowIndex
5990 * @param {Roo.EventObject} e
5992 "rowcontextmenu" : true,
5994 * @event cellcontextmenu
5995 * Fires when a cell is right clicked
5996 * @param {Roo.bootstrap.Table} this
5997 * @param {Number} rowIndex
5998 * @param {Number} cellIndex
5999 * @param {Roo.EventObject} e
6001 "cellcontextmenu" : true,
6003 * @event headercontextmenu
6004 * Fires when a header is right clicked
6005 * @param {Roo.bootstrap.Table} this
6006 * @param {Number} columnIndex
6007 * @param {Roo.EventObject} e
6009 "headercontextmenu" : true
6013 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6039 rowSelection : false,
6040 cellSelection : false,
6043 // Roo.Element - the tbody
6045 // Roo.Element - thead element
6048 container: false, // used by gridpanel...
6054 getAutoCreate : function()
6056 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6063 if (this.scrollBody) {
6064 cfg.cls += ' table-body-fixed';
6067 cfg.cls += ' table-striped';
6071 cfg.cls += ' table-hover';
6073 if (this.bordered) {
6074 cfg.cls += ' table-bordered';
6076 if (this.condensed) {
6077 cfg.cls += ' table-condensed';
6079 if (this.responsive) {
6080 cfg.cls += ' table-responsive';
6084 cfg.cls+= ' ' +this.cls;
6087 // this lot should be simplifed...
6090 cfg.align=this.align;
6093 cfg.bgcolor=this.bgcolor;
6096 cfg.border=this.border;
6098 if (this.cellpadding) {
6099 cfg.cellpadding=this.cellpadding;
6101 if (this.cellspacing) {
6102 cfg.cellspacing=this.cellspacing;
6105 cfg.frame=this.frame;
6108 cfg.rules=this.rules;
6110 if (this.sortable) {
6111 cfg.sortable=this.sortable;
6114 cfg.summary=this.summary;
6117 cfg.width=this.width;
6120 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6123 if(this.store || this.cm){
6124 if(this.headerShow){
6125 cfg.cn.push(this.renderHeader());
6128 cfg.cn.push(this.renderBody());
6130 if(this.footerShow){
6131 cfg.cn.push(this.renderFooter());
6133 // where does this come from?
6134 //cfg.cls+= ' TableGrid';
6137 return { cn : [ cfg ] };
6140 initEvents : function()
6142 if(!this.store || !this.cm){
6145 if (this.selModel) {
6146 this.selModel.initEvents();
6150 //Roo.log('initEvents with ds!!!!');
6152 this.mainBody = this.el.select('tbody', true).first();
6153 this.mainHead = this.el.select('thead', true).first();
6160 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6161 e.on('click', _this.sort, _this);
6164 this.mainBody.on("click", this.onClick, this);
6165 this.mainBody.on("dblclick", this.onDblClick, this);
6167 // why is this done????? = it breaks dialogs??
6168 //this.parent().el.setStyle('position', 'relative');
6172 this.footer.parentId = this.id;
6173 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6176 this.el.select('tfoot tr td').first().addClass('hide');
6180 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6182 this.store.on('load', this.onLoad, this);
6183 this.store.on('beforeload', this.onBeforeLoad, this);
6184 this.store.on('update', this.onUpdate, this);
6185 this.store.on('add', this.onAdd, this);
6186 this.store.on("clear", this.clear, this);
6188 this.el.on("contextmenu", this.onContextMenu, this);
6190 this.mainBody.on('scroll', this.onBodyScroll, this);
6192 this.cm.on("headerchange", this.onHeaderChange, this);
6194 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6198 onContextMenu : function(e, t)
6200 this.processEvent("contextmenu", e);
6203 processEvent : function(name, e)
6205 if (name != 'touchstart' ) {
6206 this.fireEvent(name, e);
6209 var t = e.getTarget();
6211 var cell = Roo.get(t);
6217 if(cell.findParent('tfoot', false, true)){
6221 if(cell.findParent('thead', false, true)){
6223 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6224 cell = Roo.get(t).findParent('th', false, true);
6226 Roo.log("failed to find th in thead?");
6227 Roo.log(e.getTarget());
6232 var cellIndex = cell.dom.cellIndex;
6234 var ename = name == 'touchstart' ? 'click' : name;
6235 this.fireEvent("header" + ename, this, cellIndex, e);
6240 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6241 cell = Roo.get(t).findParent('td', false, true);
6243 Roo.log("failed to find th in tbody?");
6244 Roo.log(e.getTarget());
6249 var row = cell.findParent('tr', false, true);
6250 var cellIndex = cell.dom.cellIndex;
6251 var rowIndex = row.dom.rowIndex - 1;
6255 this.fireEvent("row" + name, this, rowIndex, e);
6259 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6265 onMouseover : function(e, el)
6267 var cell = Roo.get(el);
6273 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6274 cell = cell.findParent('td', false, true);
6277 var row = cell.findParent('tr', false, true);
6278 var cellIndex = cell.dom.cellIndex;
6279 var rowIndex = row.dom.rowIndex - 1; // start from 0
6281 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6285 onMouseout : function(e, el)
6287 var cell = Roo.get(el);
6293 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6294 cell = cell.findParent('td', false, true);
6297 var row = cell.findParent('tr', false, true);
6298 var cellIndex = cell.dom.cellIndex;
6299 var rowIndex = row.dom.rowIndex - 1; // start from 0
6301 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6305 onClick : function(e, el)
6307 var cell = Roo.get(el);
6309 if(!cell || (!this.cellSelection && !this.rowSelection)){
6313 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6314 cell = cell.findParent('td', false, true);
6317 if(!cell || typeof(cell) == 'undefined'){
6321 var row = cell.findParent('tr', false, true);
6323 if(!row || typeof(row) == 'undefined'){
6327 var cellIndex = cell.dom.cellIndex;
6328 var rowIndex = this.getRowIndex(row);
6330 // why??? - should these not be based on SelectionModel?
6331 if(this.cellSelection){
6332 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6335 if(this.rowSelection){
6336 this.fireEvent('rowclick', this, row, rowIndex, e);
6342 onDblClick : function(e,el)
6344 var cell = Roo.get(el);
6346 if(!cell || (!this.cellSelection && !this.rowSelection)){
6350 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6351 cell = cell.findParent('td', false, true);
6354 if(!cell || typeof(cell) == 'undefined'){
6358 var row = cell.findParent('tr', false, true);
6360 if(!row || typeof(row) == 'undefined'){
6364 var cellIndex = cell.dom.cellIndex;
6365 var rowIndex = this.getRowIndex(row);
6367 if(this.cellSelection){
6368 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6371 if(this.rowSelection){
6372 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6376 sort : function(e,el)
6378 var col = Roo.get(el);
6380 if(!col.hasClass('sortable')){
6384 var sort = col.attr('sort');
6387 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6391 this.store.sortInfo = {field : sort, direction : dir};
6394 Roo.log("calling footer first");
6395 this.footer.onClick('first');
6398 this.store.load({ params : { start : 0 } });
6402 renderHeader : function()
6410 this.totalWidth = 0;
6412 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6414 var config = cm.config[i];
6418 cls : 'roo-bootstrap-thead-col-' + i,
6420 html: cm.getColumnHeader(i)
6425 if(typeof(config.sortable) != 'undefined' && config.sortable){
6427 c.html = '<i class="glyphicon"></i>' + c.html;
6430 if(typeof(config.lgHeader) != 'undefined'){
6431 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6434 if(typeof(config.mdHeader) != 'undefined'){
6435 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6438 if(typeof(config.smHeader) != 'undefined'){
6439 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6442 if(typeof(config.xsHeader) != 'undefined'){
6443 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6450 if(typeof(config.tooltip) != 'undefined'){
6451 c.tooltip = config.tooltip;
6454 if(typeof(config.colspan) != 'undefined'){
6455 c.colspan = config.colspan;
6458 if(typeof(config.hidden) != 'undefined' && config.hidden){
6459 c.style += ' display:none;';
6462 if(typeof(config.dataIndex) != 'undefined'){
6463 c.sort = config.dataIndex;
6468 if(typeof(config.align) != 'undefined' && config.align.length){
6469 c.style += ' text-align:' + config.align + ';';
6472 if(typeof(config.width) != 'undefined'){
6473 c.style += ' width:' + config.width + 'px;';
6474 this.totalWidth += config.width;
6476 this.totalWidth += 100; // assume minimum of 100 per column?
6479 if(typeof(config.cls) != 'undefined'){
6480 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6483 ['xs','sm','md','lg'].map(function(size){
6485 if(typeof(config[size]) == 'undefined'){
6489 if (!config[size]) { // 0 = hidden
6490 c.cls += ' hidden-' + size;
6494 c.cls += ' col-' + size + '-' + config[size];
6504 renderBody : function()
6514 colspan : this.cm.getColumnCount()
6524 renderFooter : function()
6534 colspan : this.cm.getColumnCount()
6548 // Roo.log('ds onload');
6553 var ds = this.store;
6555 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6556 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6557 if (_this.store.sortInfo) {
6559 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6560 e.select('i', true).addClass(['glyphicon-arrow-up']);
6563 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6564 e.select('i', true).addClass(['glyphicon-arrow-down']);
6569 var tbody = this.mainBody;
6571 if(ds.getCount() > 0){
6572 ds.data.each(function(d,rowIndex){
6573 var row = this.renderRow(cm, ds, rowIndex);
6575 tbody.createChild(row);
6579 if(row.cellObjects.length){
6580 Roo.each(row.cellObjects, function(r){
6581 _this.renderCellObject(r);
6588 Roo.each(this.el.select('tbody td', true).elements, function(e){
6589 e.on('mouseover', _this.onMouseover, _this);
6592 Roo.each(this.el.select('tbody td', true).elements, function(e){
6593 e.on('mouseout', _this.onMouseout, _this);
6595 this.fireEvent('rowsrendered', this);
6596 //if(this.loadMask){
6597 // this.maskEl.hide();
6604 onUpdate : function(ds,record)
6606 this.refreshRow(record);
6610 onRemove : function(ds, record, index, isUpdate){
6611 if(isUpdate !== true){
6612 this.fireEvent("beforerowremoved", this, index, record);
6614 var bt = this.mainBody.dom;
6616 var rows = this.el.select('tbody > tr', true).elements;
6618 if(typeof(rows[index]) != 'undefined'){
6619 bt.removeChild(rows[index].dom);
6622 // if(bt.rows[index]){
6623 // bt.removeChild(bt.rows[index]);
6626 if(isUpdate !== true){
6627 //this.stripeRows(index);
6628 //this.syncRowHeights(index, index);
6630 this.fireEvent("rowremoved", this, index, record);
6634 onAdd : function(ds, records, rowIndex)
6636 //Roo.log('on Add called');
6637 // - note this does not handle multiple adding very well..
6638 var bt = this.mainBody.dom;
6639 for (var i =0 ; i < records.length;i++) {
6640 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6641 //Roo.log(records[i]);
6642 //Roo.log(this.store.getAt(rowIndex+i));
6643 this.insertRow(this.store, rowIndex + i, false);
6650 refreshRow : function(record){
6651 var ds = this.store, index;
6652 if(typeof record == 'number'){
6654 record = ds.getAt(index);
6656 index = ds.indexOf(record);
6658 this.insertRow(ds, index, true);
6660 this.onRemove(ds, record, index+1, true);
6662 //this.syncRowHeights(index, index);
6664 this.fireEvent("rowupdated", this, index, record);
6667 insertRow : function(dm, rowIndex, isUpdate){
6670 this.fireEvent("beforerowsinserted", this, rowIndex);
6672 //var s = this.getScrollState();
6673 var row = this.renderRow(this.cm, this.store, rowIndex);
6674 // insert before rowIndex..
6675 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6679 if(row.cellObjects.length){
6680 Roo.each(row.cellObjects, function(r){
6681 _this.renderCellObject(r);
6686 this.fireEvent("rowsinserted", this, rowIndex);
6687 //this.syncRowHeights(firstRow, lastRow);
6688 //this.stripeRows(firstRow);
6695 getRowDom : function(rowIndex)
6697 var rows = this.el.select('tbody > tr', true).elements;
6699 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6702 // returns the object tree for a tr..
6705 renderRow : function(cm, ds, rowIndex)
6707 var d = ds.getAt(rowIndex);
6711 cls : 'roo-bootstrap-tbody-row-' + rowIndex,
6715 var cellObjects = [];
6717 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6718 var config = cm.config[i];
6720 var renderer = cm.getRenderer(i);
6724 if(typeof(renderer) !== 'undefined'){
6725 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6727 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6728 // and are rendered into the cells after the row is rendered - using the id for the element.
6730 if(typeof(value) === 'object'){
6740 rowIndex : rowIndex,
6745 this.fireEvent('rowclass', this, rowcfg);
6749 cls : rowcfg.rowClass + ' roo-bootstrap-tbody-col-' + i,
6751 html: (typeof(value) === 'object') ? '' : value
6758 if(typeof(config.colspan) != 'undefined'){
6759 td.colspan = config.colspan;
6762 if(typeof(config.hidden) != 'undefined' && config.hidden){
6763 td.style += ' display:none;';
6766 if(typeof(config.align) != 'undefined' && config.align.length){
6767 td.style += ' text-align:' + config.align + ';';
6770 if(typeof(config.width) != 'undefined'){
6771 td.style += ' width:' + config.width + 'px;';
6774 if(typeof(config.cursor) != 'undefined'){
6775 td.style += ' cursor:' + config.cursor + ';';
6778 if(typeof(config.cls) != 'undefined'){
6779 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6782 ['xs','sm','md','lg'].map(function(size){
6784 if(typeof(config[size]) == 'undefined'){
6788 if (!config[size]) { // 0 = hidden
6789 td.cls += ' hidden-' + size;
6793 td.cls += ' col-' + size + '-' + config[size];
6801 row.cellObjects = cellObjects;
6809 onBeforeLoad : function()
6811 //Roo.log('ds onBeforeLoad');
6815 //if(this.loadMask){
6816 // this.maskEl.show();
6824 this.el.select('tbody', true).first().dom.innerHTML = '';
6827 * Show or hide a row.
6828 * @param {Number} rowIndex to show or hide
6829 * @param {Boolean} state hide
6831 setRowVisibility : function(rowIndex, state)
6833 var bt = this.mainBody.dom;
6835 var rows = this.el.select('tbody > tr', true).elements;
6837 if(typeof(rows[rowIndex]) == 'undefined'){
6840 rows[rowIndex].dom.style.display = state ? '' : 'none';
6844 getSelectionModel : function(){
6846 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6848 return this.selModel;
6851 * Render the Roo.bootstrap object from renderder
6853 renderCellObject : function(r)
6857 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6859 var t = r.cfg.render(r.container);
6862 Roo.each(r.cfg.cn, function(c){
6864 container: t.getChildContainer(),
6867 _this.renderCellObject(child);
6872 getRowIndex : function(row)
6876 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6887 * Returns the grid's underlying element = used by panel.Grid
6888 * @return {Element} The element
6890 getGridEl : function(){
6894 * Forces a resize - used by panel.Grid
6895 * @return {Element} The element
6897 autoSize : function()
6899 //var ctr = Roo.get(this.container.dom.parentElement);
6900 var ctr = Roo.get(this.el.dom);
6902 var thd = this.getGridEl().select('thead',true).first();
6903 var tbd = this.getGridEl().select('tbody', true).first();
6904 var tfd = this.getGridEl().select('tfoot', true).first();
6906 var cw = ctr.getWidth();
6910 tbd.setSize(ctr.getWidth(),
6911 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6913 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6916 cw = Math.max(cw, this.totalWidth);
6917 this.getGridEl().select('tr',true).setWidth(cw);
6918 // resize 'expandable coloumn?
6920 return; // we doe not have a view in this design..
6923 onBodyScroll: function()
6925 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6927 this.mainHead.setStyle({
6928 'position' : 'relative',
6929 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6935 var scrollHeight = this.mainBody.dom.scrollHeight;
6937 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6939 var height = this.mainBody.getHeight();
6941 if(scrollHeight - height == scrollTop) {
6943 var total = this.ds.getTotalCount();
6945 if(this.footer.cursor + this.footer.pageSize < total){
6947 this.footer.ds.load({
6949 start : this.footer.cursor + this.footer.pageSize,
6950 limit : this.footer.pageSize
6960 onHeaderChange : function()
6963 var header = this.renderHeader();
6964 var table = this.el.select('table', true).first();
6966 this.mainHead.remove();
6967 this.mainHead = table.createChild(header, this.mainBody, false);
6970 onHiddenChange : function(colModel, colIndex, hidden)
6972 var thSelector = 'roo-bootstrap-thead-col-' + colIndex;
6973 var tdSelector = 'roo-bootstrap-tbody-col-' + colIndex;
6975 this.CSS.updateRule(thSelector, "display", "");
6976 this.CSS.updateRule(tdSelector, "display", "");
6979 this.CSS.updateRule(thSelector, "display", "none");
6980 this.CSS.updateRule(tdSelector, "display", "none");
6997 * @class Roo.bootstrap.TableCell
6998 * @extends Roo.bootstrap.Component
6999 * Bootstrap TableCell class
7000 * @cfg {String} html cell contain text
7001 * @cfg {String} cls cell class
7002 * @cfg {String} tag cell tag (td|th) default td
7003 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7004 * @cfg {String} align Aligns the content in a cell
7005 * @cfg {String} axis Categorizes cells
7006 * @cfg {String} bgcolor Specifies the background color of a cell
7007 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7008 * @cfg {Number} colspan Specifies the number of columns a cell should span
7009 * @cfg {String} headers Specifies one or more header cells a cell is related to
7010 * @cfg {Number} height Sets the height of a cell
7011 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7012 * @cfg {Number} rowspan Sets the number of rows a cell should span
7013 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7014 * @cfg {String} valign Vertical aligns the content in a cell
7015 * @cfg {Number} width Specifies the width of a cell
7018 * Create a new TableCell
7019 * @param {Object} config The config object
7022 Roo.bootstrap.TableCell = function(config){
7023 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7026 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7046 getAutoCreate : function(){
7047 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7067 cfg.align=this.align
7073 cfg.bgcolor=this.bgcolor
7076 cfg.charoff=this.charoff
7079 cfg.colspan=this.colspan
7082 cfg.headers=this.headers
7085 cfg.height=this.height
7088 cfg.nowrap=this.nowrap
7091 cfg.rowspan=this.rowspan
7094 cfg.scope=this.scope
7097 cfg.valign=this.valign
7100 cfg.width=this.width
7119 * @class Roo.bootstrap.TableRow
7120 * @extends Roo.bootstrap.Component
7121 * Bootstrap TableRow class
7122 * @cfg {String} cls row class
7123 * @cfg {String} align Aligns the content in a table row
7124 * @cfg {String} bgcolor Specifies a background color for a table row
7125 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7126 * @cfg {String} valign Vertical aligns the content in a table row
7129 * Create a new TableRow
7130 * @param {Object} config The config object
7133 Roo.bootstrap.TableRow = function(config){
7134 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7137 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7145 getAutoCreate : function(){
7146 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7156 cfg.align = this.align;
7159 cfg.bgcolor = this.bgcolor;
7162 cfg.charoff = this.charoff;
7165 cfg.valign = this.valign;
7183 * @class Roo.bootstrap.TableBody
7184 * @extends Roo.bootstrap.Component
7185 * Bootstrap TableBody class
7186 * @cfg {String} cls element class
7187 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7188 * @cfg {String} align Aligns the content inside the element
7189 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7190 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7193 * Create a new TableBody
7194 * @param {Object} config The config object
7197 Roo.bootstrap.TableBody = function(config){
7198 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7201 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7209 getAutoCreate : function(){
7210 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7224 cfg.align = this.align;
7227 cfg.charoff = this.charoff;
7230 cfg.valign = this.valign;
7237 // initEvents : function()
7244 // this.store = Roo.factory(this.store, Roo.data);
7245 // this.store.on('load', this.onLoad, this);
7247 // this.store.load();
7251 // onLoad: function ()
7253 // this.fireEvent('load', this);
7263 * Ext JS Library 1.1.1
7264 * Copyright(c) 2006-2007, Ext JS, LLC.
7266 * Originally Released Under LGPL - original licence link has changed is not relivant.
7269 * <script type="text/javascript">
7272 // as we use this in bootstrap.
7273 Roo.namespace('Roo.form');
7275 * @class Roo.form.Action
7276 * Internal Class used to handle form actions
7278 * @param {Roo.form.BasicForm} el The form element or its id
7279 * @param {Object} config Configuration options
7284 // define the action interface
7285 Roo.form.Action = function(form, options){
7287 this.options = options || {};
7290 * Client Validation Failed
7293 Roo.form.Action.CLIENT_INVALID = 'client';
7295 * Server Validation Failed
7298 Roo.form.Action.SERVER_INVALID = 'server';
7300 * Connect to Server Failed
7303 Roo.form.Action.CONNECT_FAILURE = 'connect';
7305 * Reading Data from Server Failed
7308 Roo.form.Action.LOAD_FAILURE = 'load';
7310 Roo.form.Action.prototype = {
7312 failureType : undefined,
7313 response : undefined,
7317 run : function(options){
7322 success : function(response){
7327 handleResponse : function(response){
7331 // default connection failure
7332 failure : function(response){
7334 this.response = response;
7335 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7336 this.form.afterAction(this, false);
7339 processResponse : function(response){
7340 this.response = response;
7341 if(!response.responseText){
7344 this.result = this.handleResponse(response);
7348 // utility functions used internally
7349 getUrl : function(appendParams){
7350 var url = this.options.url || this.form.url || this.form.el.dom.action;
7352 var p = this.getParams();
7354 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7360 getMethod : function(){
7361 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7364 getParams : function(){
7365 var bp = this.form.baseParams;
7366 var p = this.options.params;
7368 if(typeof p == "object"){
7369 p = Roo.urlEncode(Roo.applyIf(p, bp));
7370 }else if(typeof p == 'string' && bp){
7371 p += '&' + Roo.urlEncode(bp);
7374 p = Roo.urlEncode(bp);
7379 createCallback : function(){
7381 success: this.success,
7382 failure: this.failure,
7384 timeout: (this.form.timeout*1000),
7385 upload: this.form.fileUpload ? this.success : undefined
7390 Roo.form.Action.Submit = function(form, options){
7391 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7394 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7397 haveProgress : false,
7398 uploadComplete : false,
7400 // uploadProgress indicator.
7401 uploadProgress : function()
7403 if (!this.form.progressUrl) {
7407 if (!this.haveProgress) {
7408 Roo.MessageBox.progress("Uploading", "Uploading");
7410 if (this.uploadComplete) {
7411 Roo.MessageBox.hide();
7415 this.haveProgress = true;
7417 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7419 var c = new Roo.data.Connection();
7421 url : this.form.progressUrl,
7426 success : function(req){
7427 //console.log(data);
7431 rdata = Roo.decode(req.responseText)
7433 Roo.log("Invalid data from server..");
7437 if (!rdata || !rdata.success) {
7439 Roo.MessageBox.alert(Roo.encode(rdata));
7442 var data = rdata.data;
7444 if (this.uploadComplete) {
7445 Roo.MessageBox.hide();
7450 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7451 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7454 this.uploadProgress.defer(2000,this);
7457 failure: function(data) {
7458 Roo.log('progress url failed ');
7469 // run get Values on the form, so it syncs any secondary forms.
7470 this.form.getValues();
7472 var o = this.options;
7473 var method = this.getMethod();
7474 var isPost = method == 'POST';
7475 if(o.clientValidation === false || this.form.isValid()){
7477 if (this.form.progressUrl) {
7478 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7479 (new Date() * 1) + '' + Math.random());
7484 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7485 form:this.form.el.dom,
7486 url:this.getUrl(!isPost),
7488 params:isPost ? this.getParams() : null,
7489 isUpload: this.form.fileUpload
7492 this.uploadProgress();
7494 }else if (o.clientValidation !== false){ // client validation failed
7495 this.failureType = Roo.form.Action.CLIENT_INVALID;
7496 this.form.afterAction(this, false);
7500 success : function(response)
7502 this.uploadComplete= true;
7503 if (this.haveProgress) {
7504 Roo.MessageBox.hide();
7508 var result = this.processResponse(response);
7509 if(result === true || result.success){
7510 this.form.afterAction(this, true);
7514 this.form.markInvalid(result.errors);
7515 this.failureType = Roo.form.Action.SERVER_INVALID;
7517 this.form.afterAction(this, false);
7519 failure : function(response)
7521 this.uploadComplete= true;
7522 if (this.haveProgress) {
7523 Roo.MessageBox.hide();
7526 this.response = response;
7527 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7528 this.form.afterAction(this, false);
7531 handleResponse : function(response){
7532 if(this.form.errorReader){
7533 var rs = this.form.errorReader.read(response);
7536 for(var i = 0, len = rs.records.length; i < len; i++) {
7537 var r = rs.records[i];
7541 if(errors.length < 1){
7545 success : rs.success,
7551 ret = Roo.decode(response.responseText);
7555 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7565 Roo.form.Action.Load = function(form, options){
7566 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7567 this.reader = this.form.reader;
7570 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7575 Roo.Ajax.request(Roo.apply(
7576 this.createCallback(), {
7577 method:this.getMethod(),
7578 url:this.getUrl(false),
7579 params:this.getParams()
7583 success : function(response){
7585 var result = this.processResponse(response);
7586 if(result === true || !result.success || !result.data){
7587 this.failureType = Roo.form.Action.LOAD_FAILURE;
7588 this.form.afterAction(this, false);
7591 this.form.clearInvalid();
7592 this.form.setValues(result.data);
7593 this.form.afterAction(this, true);
7596 handleResponse : function(response){
7597 if(this.form.reader){
7598 var rs = this.form.reader.read(response);
7599 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7601 success : rs.success,
7605 return Roo.decode(response.responseText);
7609 Roo.form.Action.ACTION_TYPES = {
7610 'load' : Roo.form.Action.Load,
7611 'submit' : Roo.form.Action.Submit
7620 * @class Roo.bootstrap.Form
7621 * @extends Roo.bootstrap.Component
7622 * Bootstrap Form class
7623 * @cfg {String} method GET | POST (default POST)
7624 * @cfg {String} labelAlign top | left (default top)
7625 * @cfg {String} align left | right - for navbars
7626 * @cfg {Boolean} loadMask load mask when submit (default true)
7631 * @param {Object} config The config object
7635 Roo.bootstrap.Form = function(config){
7637 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7639 Roo.bootstrap.Form.popover.apply();
7643 * @event clientvalidation
7644 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7645 * @param {Form} this
7646 * @param {Boolean} valid true if the form has passed client-side validation
7648 clientvalidation: true,
7650 * @event beforeaction
7651 * Fires before any action is performed. Return false to cancel the action.
7652 * @param {Form} this
7653 * @param {Action} action The action to be performed
7657 * @event actionfailed
7658 * Fires when an action fails.
7659 * @param {Form} this
7660 * @param {Action} action The action that failed
7662 actionfailed : true,
7664 * @event actioncomplete
7665 * Fires when an action is completed.
7666 * @param {Form} this
7667 * @param {Action} action The action that completed
7669 actioncomplete : true
7673 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7676 * @cfg {String} method
7677 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7682 * The URL to use for form actions if one isn't supplied in the action options.
7685 * @cfg {Boolean} fileUpload
7686 * Set to true if this form is a file upload.
7690 * @cfg {Object} baseParams
7691 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7695 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7699 * @cfg {Sting} align (left|right) for navbar forms
7704 activeAction : null,
7707 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7708 * element by passing it or its id or mask the form itself by passing in true.
7711 waitMsgTarget : false,
7716 * @cfg {Boolean} errorMask (true|false) default false
7721 * @cfg {Number} maskOffset Default 100
7726 * @cfg {Boolean} maskBody
7730 getAutoCreate : function(){
7734 method : this.method || 'POST',
7735 id : this.id || Roo.id(),
7738 if (this.parent().xtype.match(/^Nav/)) {
7739 cfg.cls = 'navbar-form navbar-' + this.align;
7743 if (this.labelAlign == 'left' ) {
7744 cfg.cls += ' form-horizontal';
7750 initEvents : function()
7752 this.el.on('submit', this.onSubmit, this);
7753 // this was added as random key presses on the form where triggering form submit.
7754 this.el.on('keypress', function(e) {
7755 if (e.getCharCode() != 13) {
7758 // we might need to allow it for textareas.. and some other items.
7759 // check e.getTarget().
7761 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7765 Roo.log("keypress blocked");
7773 onSubmit : function(e){
7778 * Returns true if client-side validation on the form is successful.
7781 isValid : function(){
7782 var items = this.getItems();
7786 items.each(function(f){
7792 if(!target && f.el.isVisible(true)){
7798 if(this.errorMask && !valid){
7799 Roo.bootstrap.Form.popover.mask(this, target);
7806 * Returns true if any fields in this form have changed since their original load.
7809 isDirty : function(){
7811 var items = this.getItems();
7812 items.each(function(f){
7822 * Performs a predefined action (submit or load) or custom actions you define on this form.
7823 * @param {String} actionName The name of the action type
7824 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7825 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7826 * accept other config options):
7828 Property Type Description
7829 ---------------- --------------- ----------------------------------------------------------------------------------
7830 url String The url for the action (defaults to the form's url)
7831 method String The form method to use (defaults to the form's method, or POST if not defined)
7832 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7833 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7834 validate the form on the client (defaults to false)
7836 * @return {BasicForm} this
7838 doAction : function(action, options){
7839 if(typeof action == 'string'){
7840 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7842 if(this.fireEvent('beforeaction', this, action) !== false){
7843 this.beforeAction(action);
7844 action.run.defer(100, action);
7850 beforeAction : function(action){
7851 var o = action.options;
7856 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7858 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7861 // not really supported yet.. ??
7863 //if(this.waitMsgTarget === true){
7864 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7865 //}else if(this.waitMsgTarget){
7866 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7867 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7869 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7875 afterAction : function(action, success){
7876 this.activeAction = null;
7877 var o = action.options;
7882 Roo.get(document.body).unmask();
7888 //if(this.waitMsgTarget === true){
7889 // this.el.unmask();
7890 //}else if(this.waitMsgTarget){
7891 // this.waitMsgTarget.unmask();
7893 // Roo.MessageBox.updateProgress(1);
7894 // Roo.MessageBox.hide();
7901 Roo.callback(o.success, o.scope, [this, action]);
7902 this.fireEvent('actioncomplete', this, action);
7906 // failure condition..
7907 // we have a scenario where updates need confirming.
7908 // eg. if a locking scenario exists..
7909 // we look for { errors : { needs_confirm : true }} in the response.
7911 (typeof(action.result) != 'undefined') &&
7912 (typeof(action.result.errors) != 'undefined') &&
7913 (typeof(action.result.errors.needs_confirm) != 'undefined')
7916 Roo.log("not supported yet");
7919 Roo.MessageBox.confirm(
7920 "Change requires confirmation",
7921 action.result.errorMsg,
7926 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7936 Roo.callback(o.failure, o.scope, [this, action]);
7937 // show an error message if no failed handler is set..
7938 if (!this.hasListener('actionfailed')) {
7939 Roo.log("need to add dialog support");
7941 Roo.MessageBox.alert("Error",
7942 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7943 action.result.errorMsg :
7944 "Saving Failed, please check your entries or try again"
7949 this.fireEvent('actionfailed', this, action);
7954 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7955 * @param {String} id The value to search for
7958 findField : function(id){
7959 var items = this.getItems();
7960 var field = items.get(id);
7962 items.each(function(f){
7963 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7970 return field || null;
7973 * Mark fields in this form invalid in bulk.
7974 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7975 * @return {BasicForm} this
7977 markInvalid : function(errors){
7978 if(errors instanceof Array){
7979 for(var i = 0, len = errors.length; i < len; i++){
7980 var fieldError = errors[i];
7981 var f = this.findField(fieldError.id);
7983 f.markInvalid(fieldError.msg);
7989 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7990 field.markInvalid(errors[id]);
7994 //Roo.each(this.childForms || [], function (f) {
7995 // f.markInvalid(errors);
8002 * Set values for fields in this form in bulk.
8003 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8004 * @return {BasicForm} this
8006 setValues : function(values){
8007 if(values instanceof Array){ // array of objects
8008 for(var i = 0, len = values.length; i < len; i++){
8010 var f = this.findField(v.id);
8012 f.setValue(v.value);
8013 if(this.trackResetOnLoad){
8014 f.originalValue = f.getValue();
8018 }else{ // object hash
8021 if(typeof values[id] != 'function' && (field = this.findField(id))){
8023 if (field.setFromData &&
8025 field.displayField &&
8026 // combos' with local stores can
8027 // be queried via setValue()
8028 // to set their value..
8029 (field.store && !field.store.isLocal)
8033 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8034 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8035 field.setFromData(sd);
8037 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8039 field.setFromData(values);
8042 field.setValue(values[id]);
8046 if(this.trackResetOnLoad){
8047 field.originalValue = field.getValue();
8053 //Roo.each(this.childForms || [], function (f) {
8054 // f.setValues(values);
8061 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8062 * they are returned as an array.
8063 * @param {Boolean} asString
8066 getValues : function(asString){
8067 //if (this.childForms) {
8068 // copy values from the child forms
8069 // Roo.each(this.childForms, function (f) {
8070 // this.setValues(f.getValues());
8076 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8077 if(asString === true){
8080 return Roo.urlDecode(fs);
8084 * Returns the fields in this form as an object with key/value pairs.
8085 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8088 getFieldValues : function(with_hidden)
8090 var items = this.getItems();
8092 items.each(function(f){
8098 var v = f.getValue();
8100 if (f.inputType =='radio') {
8101 if (typeof(ret[f.getName()]) == 'undefined') {
8102 ret[f.getName()] = ''; // empty..
8105 if (!f.el.dom.checked) {
8113 if(f.xtype == 'MoneyField'){
8114 ret[f.currencyName] = f.getCurrency();
8117 // not sure if this supported any more..
8118 if ((typeof(v) == 'object') && f.getRawValue) {
8119 v = f.getRawValue() ; // dates..
8121 // combo boxes where name != hiddenName...
8122 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8123 ret[f.name] = f.getRawValue();
8125 ret[f.getName()] = v;
8132 * Clears all invalid messages in this form.
8133 * @return {BasicForm} this
8135 clearInvalid : function(){
8136 var items = this.getItems();
8138 items.each(function(f){
8147 * @return {BasicForm} this
8150 var items = this.getItems();
8151 items.each(function(f){
8155 Roo.each(this.childForms || [], function (f) {
8163 getItems : function()
8165 var r=new Roo.util.MixedCollection(false, function(o){
8166 return o.id || (o.id = Roo.id());
8168 var iter = function(el) {
8175 Roo.each(el.items,function(e) {
8184 hideFields : function(items)
8186 Roo.each(items, function(i){
8188 var f = this.findField(i);
8194 if(f.xtype == 'DateField'){
8195 f.setVisible(false);
8204 showFields : function(items)
8206 Roo.each(items, function(i){
8208 var f = this.findField(i);
8214 if(f.xtype == 'DateField'){
8226 Roo.apply(Roo.bootstrap.Form, {
8253 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8254 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8255 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8256 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8259 this.maskEl.top.enableDisplayMode("block");
8260 this.maskEl.left.enableDisplayMode("block");
8261 this.maskEl.bottom.enableDisplayMode("block");
8262 this.maskEl.right.enableDisplayMode("block");
8264 this.toolTip = new Roo.bootstrap.Tooltip({
8265 cls : 'roo-form-error-popover',
8267 'left' : ['r-l', [-2,0], 'right'],
8268 'right' : ['l-r', [2,0], 'left'],
8269 'bottom' : ['tl-bl', [0,2], 'top'],
8270 'top' : [ 'bl-tl', [0,-2], 'bottom']
8274 this.toolTip.render(Roo.get(document.body));
8276 this.toolTip.el.enableDisplayMode("block");
8278 Roo.get(document.body).on('click', function(){
8282 Roo.get(document.body).on('touchstart', function(){
8286 this.isApplied = true
8289 mask : function(form, target)
8293 this.target = target;
8295 if(!this.form.errorMask || !target.el){
8299 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8301 Roo.log(scrollable);
8303 var ot = this.target.el.calcOffsetsTo(scrollable);
8305 var scrollTo = ot[1] - this.form.maskOffset;
8307 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8309 scrollable.scrollTo('top', scrollTo);
8311 var box = this.target.el.getBox();
8313 var zIndex = Roo.bootstrap.Modal.zIndex++;
8316 this.maskEl.top.setStyle('position', 'absolute');
8317 this.maskEl.top.setStyle('z-index', zIndex);
8318 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8319 this.maskEl.top.setLeft(0);
8320 this.maskEl.top.setTop(0);
8321 this.maskEl.top.show();
8323 this.maskEl.left.setStyle('position', 'absolute');
8324 this.maskEl.left.setStyle('z-index', zIndex);
8325 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8326 this.maskEl.left.setLeft(0);
8327 this.maskEl.left.setTop(box.y - this.padding);
8328 this.maskEl.left.show();
8330 this.maskEl.bottom.setStyle('position', 'absolute');
8331 this.maskEl.bottom.setStyle('z-index', zIndex);
8332 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8333 this.maskEl.bottom.setLeft(0);
8334 this.maskEl.bottom.setTop(box.bottom + this.padding);
8335 this.maskEl.bottom.show();
8337 this.maskEl.right.setStyle('position', 'absolute');
8338 this.maskEl.right.setStyle('z-index', zIndex);
8339 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8340 this.maskEl.right.setLeft(box.right + this.padding);
8341 this.maskEl.right.setTop(box.y - this.padding);
8342 this.maskEl.right.show();
8344 this.toolTip.bindEl = this.target.el;
8346 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8348 var tip = this.target.blankText;
8350 if(this.target.getValue() !== '' ) {
8352 if (this.target.invalidText.length) {
8353 tip = this.target.invalidText;
8354 } else if (this.target.regexText.length){
8355 tip = this.target.regexText;
8359 this.toolTip.show(tip);
8361 this.intervalID = window.setInterval(function() {
8362 Roo.bootstrap.Form.popover.unmask();
8365 window.onwheel = function(){ return false;};
8367 (function(){ this.isMasked = true; }).defer(500, this);
8373 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8377 this.maskEl.top.setStyle('position', 'absolute');
8378 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8379 this.maskEl.top.hide();
8381 this.maskEl.left.setStyle('position', 'absolute');
8382 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8383 this.maskEl.left.hide();
8385 this.maskEl.bottom.setStyle('position', 'absolute');
8386 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8387 this.maskEl.bottom.hide();
8389 this.maskEl.right.setStyle('position', 'absolute');
8390 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8391 this.maskEl.right.hide();
8393 this.toolTip.hide();
8395 this.toolTip.el.hide();
8397 window.onwheel = function(){ return true;};
8399 if(this.intervalID){
8400 window.clearInterval(this.intervalID);
8401 this.intervalID = false;
8404 this.isMasked = false;
8414 * Ext JS Library 1.1.1
8415 * Copyright(c) 2006-2007, Ext JS, LLC.
8417 * Originally Released Under LGPL - original licence link has changed is not relivant.
8420 * <script type="text/javascript">
8423 * @class Roo.form.VTypes
8424 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8427 Roo.form.VTypes = function(){
8428 // closure these in so they are only created once.
8429 var alpha = /^[a-zA-Z_]+$/;
8430 var alphanum = /^[a-zA-Z0-9_]+$/;
8431 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8432 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8434 // All these messages and functions are configurable
8437 * The function used to validate email addresses
8438 * @param {String} value The email address
8440 'email' : function(v){
8441 return email.test(v);
8444 * The error text to display when the email validation function returns false
8447 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8449 * The keystroke filter mask to be applied on email input
8452 'emailMask' : /[a-z0-9_\.\-@]/i,
8455 * The function used to validate URLs
8456 * @param {String} value The URL
8458 'url' : function(v){
8462 * The error text to display when the url validation function returns false
8465 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8468 * The function used to validate alpha values
8469 * @param {String} value The value
8471 'alpha' : function(v){
8472 return alpha.test(v);
8475 * The error text to display when the alpha validation function returns false
8478 'alphaText' : 'This field should only contain letters and _',
8480 * The keystroke filter mask to be applied on alpha input
8483 'alphaMask' : /[a-z_]/i,
8486 * The function used to validate alphanumeric values
8487 * @param {String} value The value
8489 'alphanum' : function(v){
8490 return alphanum.test(v);
8493 * The error text to display when the alphanumeric validation function returns false
8496 'alphanumText' : 'This field should only contain letters, numbers and _',
8498 * The keystroke filter mask to be applied on alphanumeric input
8501 'alphanumMask' : /[a-z0-9_]/i
8511 * @class Roo.bootstrap.Input
8512 * @extends Roo.bootstrap.Component
8513 * Bootstrap Input class
8514 * @cfg {Boolean} disabled is it disabled
8515 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8516 * @cfg {String} name name of the input
8517 * @cfg {string} fieldLabel - the label associated
8518 * @cfg {string} placeholder - placeholder to put in text.
8519 * @cfg {string} before - input group add on before
8520 * @cfg {string} after - input group add on after
8521 * @cfg {string} size - (lg|sm) or leave empty..
8522 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8523 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8524 * @cfg {Number} md colspan out of 12 for computer-sized screens
8525 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8526 * @cfg {string} value default value of the input
8527 * @cfg {Number} labelWidth set the width of label
8528 * @cfg {Number} labellg set the width of label (1-12)
8529 * @cfg {Number} labelmd set the width of label (1-12)
8530 * @cfg {Number} labelsm set the width of label (1-12)
8531 * @cfg {Number} labelxs set the width of label (1-12)
8532 * @cfg {String} labelAlign (top|left)
8533 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8534 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8535 * @cfg {String} indicatorpos (left|right) default left
8537 * @cfg {String} align (left|center|right) Default left
8538 * @cfg {Boolean} forceFeedback (true|false) Default false
8541 * Create a new Input
8542 * @param {Object} config The config object
8545 Roo.bootstrap.Input = function(config){
8547 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8552 * Fires when this field receives input focus.
8553 * @param {Roo.form.Field} this
8558 * Fires when this field loses input focus.
8559 * @param {Roo.form.Field} this
8564 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8565 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8566 * @param {Roo.form.Field} this
8567 * @param {Roo.EventObject} e The event object
8572 * Fires just before the field blurs if the field value has changed.
8573 * @param {Roo.form.Field} this
8574 * @param {Mixed} newValue The new value
8575 * @param {Mixed} oldValue The original value
8580 * Fires after the field has been marked as invalid.
8581 * @param {Roo.form.Field} this
8582 * @param {String} msg The validation message
8587 * Fires after the field has been validated with no errors.
8588 * @param {Roo.form.Field} this
8593 * Fires after the key up
8594 * @param {Roo.form.Field} this
8595 * @param {Roo.EventObject} e The event Object
8601 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8603 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8604 automatic validation (defaults to "keyup").
8606 validationEvent : "keyup",
8608 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8610 validateOnBlur : true,
8612 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8614 validationDelay : 250,
8616 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8618 focusClass : "x-form-focus", // not needed???
8622 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8624 invalidClass : "has-warning",
8627 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8629 validClass : "has-success",
8632 * @cfg {Boolean} hasFeedback (true|false) default true
8637 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8639 invalidFeedbackClass : "glyphicon-warning-sign",
8642 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8644 validFeedbackClass : "glyphicon-ok",
8647 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8649 selectOnFocus : false,
8652 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8656 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8661 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8663 disableKeyFilter : false,
8666 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8670 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8674 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8676 blankText : "Please complete this mandatory field",
8679 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8683 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8685 maxLength : Number.MAX_VALUE,
8687 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8689 minLengthText : "The minimum length for this field is {0}",
8691 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8693 maxLengthText : "The maximum length for this field is {0}",
8697 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8698 * If available, this function will be called only after the basic validators all return true, and will be passed the
8699 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8703 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8704 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8705 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8709 * @cfg {String} regexText -- Depricated - use Invalid Text
8714 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8720 autocomplete: false,
8739 formatedValue : false,
8740 forceFeedback : false,
8742 indicatorpos : 'left',
8749 parentLabelAlign : function()
8752 while (parent.parent()) {
8753 parent = parent.parent();
8754 if (typeof(parent.labelAlign) !='undefined') {
8755 return parent.labelAlign;
8762 getAutoCreate : function()
8764 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8770 if(this.inputType != 'hidden'){
8771 cfg.cls = 'form-group' //input-group
8777 type : this.inputType,
8779 cls : 'form-control',
8780 placeholder : this.placeholder || '',
8781 autocomplete : this.autocomplete || 'new-password'
8785 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8788 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8789 input.maxLength = this.maxLength;
8792 if (this.disabled) {
8793 input.disabled=true;
8796 if (this.readOnly) {
8797 input.readonly=true;
8801 input.name = this.name;
8805 input.cls += ' input-' + this.size;
8809 ['xs','sm','md','lg'].map(function(size){
8810 if (settings[size]) {
8811 cfg.cls += ' col-' + size + '-' + settings[size];
8815 var inputblock = input;
8819 cls: 'glyphicon form-control-feedback'
8822 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8825 cls : 'has-feedback',
8833 if (this.before || this.after) {
8836 cls : 'input-group',
8840 if (this.before && typeof(this.before) == 'string') {
8842 inputblock.cn.push({
8844 cls : 'roo-input-before input-group-addon',
8848 if (this.before && typeof(this.before) == 'object') {
8849 this.before = Roo.factory(this.before);
8851 inputblock.cn.push({
8853 cls : 'roo-input-before input-group-' +
8854 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8858 inputblock.cn.push(input);
8860 if (this.after && typeof(this.after) == 'string') {
8861 inputblock.cn.push({
8863 cls : 'roo-input-after input-group-addon',
8867 if (this.after && typeof(this.after) == 'object') {
8868 this.after = Roo.factory(this.after);
8870 inputblock.cn.push({
8872 cls : 'roo-input-after input-group-' +
8873 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8877 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8878 inputblock.cls += ' has-feedback';
8879 inputblock.cn.push(feedback);
8883 if (align ==='left' && this.fieldLabel.length) {
8885 cfg.cls += ' roo-form-group-label-left';
8890 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8891 tooltip : 'This field is required'
8896 cls : 'control-label',
8897 html : this.fieldLabel
8908 var labelCfg = cfg.cn[1];
8909 var contentCfg = cfg.cn[2];
8911 if(this.indicatorpos == 'right'){
8916 cls : 'control-label',
8920 html : this.fieldLabel
8924 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8925 tooltip : 'This field is required'
8938 labelCfg = cfg.cn[0];
8939 contentCfg = cfg.cn[1];
8943 if(this.labelWidth > 12){
8944 labelCfg.style = "width: " + this.labelWidth + 'px';
8947 if(this.labelWidth < 13 && this.labelmd == 0){
8948 this.labelmd = this.labelWidth;
8951 if(this.labellg > 0){
8952 labelCfg.cls += ' col-lg-' + this.labellg;
8953 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8956 if(this.labelmd > 0){
8957 labelCfg.cls += ' col-md-' + this.labelmd;
8958 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8961 if(this.labelsm > 0){
8962 labelCfg.cls += ' col-sm-' + this.labelsm;
8963 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8966 if(this.labelxs > 0){
8967 labelCfg.cls += ' col-xs-' + this.labelxs;
8968 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8972 } else if ( this.fieldLabel.length) {
8977 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8978 tooltip : 'This field is required'
8982 //cls : 'input-group-addon',
8983 html : this.fieldLabel
8991 if(this.indicatorpos == 'right'){
8996 //cls : 'input-group-addon',
8997 html : this.fieldLabel
9002 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9003 tooltip : 'This field is required'
9023 if (this.parentType === 'Navbar' && this.parent().bar) {
9024 cfg.cls += ' navbar-form';
9027 if (this.parentType === 'NavGroup') {
9028 cfg.cls += ' navbar-form';
9036 * return the real input element.
9038 inputEl: function ()
9040 return this.el.select('input.form-control',true).first();
9043 tooltipEl : function()
9045 return this.inputEl();
9048 indicatorEl : function()
9050 var indicator = this.el.select('i.roo-required-indicator',true).first();
9060 setDisabled : function(v)
9062 var i = this.inputEl().dom;
9064 i.removeAttribute('disabled');
9068 i.setAttribute('disabled','true');
9070 initEvents : function()
9073 this.inputEl().on("keydown" , this.fireKey, this);
9074 this.inputEl().on("focus", this.onFocus, this);
9075 this.inputEl().on("blur", this.onBlur, this);
9077 this.inputEl().relayEvent('keyup', this);
9079 this.indicator = this.indicatorEl();
9082 this.indicator.addClass('invisible');
9085 // reference to original value for reset
9086 this.originalValue = this.getValue();
9087 //Roo.form.TextField.superclass.initEvents.call(this);
9088 if(this.validationEvent == 'keyup'){
9089 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9090 this.inputEl().on('keyup', this.filterValidation, this);
9092 else if(this.validationEvent !== false){
9093 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9096 if(this.selectOnFocus){
9097 this.on("focus", this.preFocus, this);
9100 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9101 this.inputEl().on("keypress", this.filterKeys, this);
9103 this.inputEl().relayEvent('keypress', this);
9106 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9107 this.el.on("click", this.autoSize, this);
9110 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9111 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9114 if (typeof(this.before) == 'object') {
9115 this.before.render(this.el.select('.roo-input-before',true).first());
9117 if (typeof(this.after) == 'object') {
9118 this.after.render(this.el.select('.roo-input-after',true).first());
9123 filterValidation : function(e){
9124 if(!e.isNavKeyPress()){
9125 this.validationTask.delay(this.validationDelay);
9129 * Validates the field value
9130 * @return {Boolean} True if the value is valid, else false
9132 validate : function(){
9133 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9134 if(this.disabled || this.validateValue(this.getRawValue())){
9145 * Validates a value according to the field's validation rules and marks the field as invalid
9146 * if the validation fails
9147 * @param {Mixed} value The value to validate
9148 * @return {Boolean} True if the value is valid, else false
9150 validateValue : function(value)
9152 if(this.getVisibilityEl().hasClass('hidden')){
9156 if(value.length < 1) { // if it's blank
9157 if(this.allowBlank){
9163 if(value.length < this.minLength){
9166 if(value.length > this.maxLength){
9170 var vt = Roo.form.VTypes;
9171 if(!vt[this.vtype](value, this)){
9175 if(typeof this.validator == "function"){
9176 var msg = this.validator(value);
9180 if (typeof(msg) == 'string') {
9181 this.invalidText = msg;
9185 if(this.regex && !this.regex.test(value)){
9193 fireKey : function(e){
9194 //Roo.log('field ' + e.getKey());
9195 if(e.isNavKeyPress()){
9196 this.fireEvent("specialkey", this, e);
9199 focus : function (selectText){
9201 this.inputEl().focus();
9202 if(selectText === true){
9203 this.inputEl().dom.select();
9209 onFocus : function(){
9210 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9211 // this.el.addClass(this.focusClass);
9214 this.hasFocus = true;
9215 this.startValue = this.getValue();
9216 this.fireEvent("focus", this);
9220 beforeBlur : Roo.emptyFn,
9224 onBlur : function(){
9226 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9227 //this.el.removeClass(this.focusClass);
9229 this.hasFocus = false;
9230 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9233 var v = this.getValue();
9234 if(String(v) !== String(this.startValue)){
9235 this.fireEvent('change', this, v, this.startValue);
9237 this.fireEvent("blur", this);
9241 * Resets the current field value to the originally loaded value and clears any validation messages
9244 this.setValue(this.originalValue);
9248 * Returns the name of the field
9249 * @return {Mixed} name The name field
9251 getName: function(){
9255 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9256 * @return {Mixed} value The field value
9258 getValue : function(){
9260 var v = this.inputEl().getValue();
9265 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9266 * @return {Mixed} value The field value
9268 getRawValue : function(){
9269 var v = this.inputEl().getValue();
9275 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9276 * @param {Mixed} value The value to set
9278 setRawValue : function(v){
9279 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9282 selectText : function(start, end){
9283 var v = this.getRawValue();
9285 start = start === undefined ? 0 : start;
9286 end = end === undefined ? v.length : end;
9287 var d = this.inputEl().dom;
9288 if(d.setSelectionRange){
9289 d.setSelectionRange(start, end);
9290 }else if(d.createTextRange){
9291 var range = d.createTextRange();
9292 range.moveStart("character", start);
9293 range.moveEnd("character", v.length-end);
9300 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9301 * @param {Mixed} value The value to set
9303 setValue : function(v){
9306 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9312 processValue : function(value){
9313 if(this.stripCharsRe){
9314 var newValue = value.replace(this.stripCharsRe, '');
9315 if(newValue !== value){
9316 this.setRawValue(newValue);
9323 preFocus : function(){
9325 if(this.selectOnFocus){
9326 this.inputEl().dom.select();
9329 filterKeys : function(e){
9331 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9334 var c = e.getCharCode(), cc = String.fromCharCode(c);
9335 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9338 if(!this.maskRe.test(cc)){
9343 * Clear any invalid styles/messages for this field
9345 clearInvalid : function(){
9347 if(!this.el || this.preventMark){ // not rendered
9352 this.el.removeClass(this.invalidClass);
9354 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9356 var feedback = this.el.select('.form-control-feedback', true).first();
9359 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9364 this.fireEvent('valid', this);
9368 * Mark this field as valid
9370 markValid : function()
9372 if(!this.el || this.preventMark){ // not rendered...
9376 this.el.removeClass([this.invalidClass, this.validClass]);
9378 var feedback = this.el.select('.form-control-feedback', true).first();
9381 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9385 this.indicator.removeClass('visible');
9386 this.indicator.addClass('invisible');
9393 if(this.allowBlank && !this.getRawValue().length){
9397 this.el.addClass(this.validClass);
9399 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9401 var feedback = this.el.select('.form-control-feedback', true).first();
9404 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9405 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9410 this.fireEvent('valid', this);
9414 * Mark this field as invalid
9415 * @param {String} msg The validation message
9417 markInvalid : function(msg)
9419 if(!this.el || this.preventMark){ // not rendered
9423 this.el.removeClass([this.invalidClass, this.validClass]);
9425 var feedback = this.el.select('.form-control-feedback', true).first();
9428 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9435 if(this.allowBlank && !this.getRawValue().length){
9440 this.indicator.removeClass('invisible');
9441 this.indicator.addClass('visible');
9444 this.el.addClass(this.invalidClass);
9446 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9448 var feedback = this.el.select('.form-control-feedback', true).first();
9451 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9453 if(this.getValue().length || this.forceFeedback){
9454 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9461 this.fireEvent('invalid', this, msg);
9464 SafariOnKeyDown : function(event)
9466 // this is a workaround for a password hang bug on chrome/ webkit.
9467 if (this.inputEl().dom.type != 'password') {
9471 var isSelectAll = false;
9473 if(this.inputEl().dom.selectionEnd > 0){
9474 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9476 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9477 event.preventDefault();
9482 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9484 event.preventDefault();
9485 // this is very hacky as keydown always get's upper case.
9487 var cc = String.fromCharCode(event.getCharCode());
9488 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9492 adjustWidth : function(tag, w){
9493 tag = tag.toLowerCase();
9494 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9495 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9499 if(tag == 'textarea'){
9502 }else if(Roo.isOpera){
9506 if(tag == 'textarea'){
9514 setFieldLabel : function(v)
9521 var ar = this.el.select('label > span',true);
9523 if (ar.elements.length) {
9524 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9525 this.fieldLabel = v;
9529 var br = this.el.select('label',true);
9531 if(br.elements.length) {
9532 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9533 this.fieldLabel = v;
9537 Roo.log('Cannot Found any of label > span || label in input');
9541 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9542 this.fieldLabel = v;
9557 * @class Roo.bootstrap.TextArea
9558 * @extends Roo.bootstrap.Input
9559 * Bootstrap TextArea class
9560 * @cfg {Number} cols Specifies the visible width of a text area
9561 * @cfg {Number} rows Specifies the visible number of lines in a text area
9562 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9563 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9564 * @cfg {string} html text
9567 * Create a new TextArea
9568 * @param {Object} config The config object
9571 Roo.bootstrap.TextArea = function(config){
9572 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9576 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9586 getAutoCreate : function(){
9588 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9594 if(this.inputType != 'hidden'){
9595 cfg.cls = 'form-group' //input-group
9603 value : this.value || '',
9604 html: this.html || '',
9605 cls : 'form-control',
9606 placeholder : this.placeholder || ''
9610 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9611 input.maxLength = this.maxLength;
9615 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9619 input.cols = this.cols;
9622 if (this.readOnly) {
9623 input.readonly = true;
9627 input.name = this.name;
9631 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9635 ['xs','sm','md','lg'].map(function(size){
9636 if (settings[size]) {
9637 cfg.cls += ' col-' + size + '-' + settings[size];
9641 var inputblock = input;
9643 if(this.hasFeedback && !this.allowBlank){
9647 cls: 'glyphicon form-control-feedback'
9651 cls : 'has-feedback',
9660 if (this.before || this.after) {
9663 cls : 'input-group',
9667 inputblock.cn.push({
9669 cls : 'input-group-addon',
9674 inputblock.cn.push(input);
9676 if(this.hasFeedback && !this.allowBlank){
9677 inputblock.cls += ' has-feedback';
9678 inputblock.cn.push(feedback);
9682 inputblock.cn.push({
9684 cls : 'input-group-addon',
9691 if (align ==='left' && this.fieldLabel.length) {
9696 cls : 'control-label',
9697 html : this.fieldLabel
9708 if(this.labelWidth > 12){
9709 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9712 if(this.labelWidth < 13 && this.labelmd == 0){
9713 this.labelmd = this.labelWidth;
9716 if(this.labellg > 0){
9717 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9718 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9721 if(this.labelmd > 0){
9722 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9723 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9726 if(this.labelsm > 0){
9727 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9728 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9731 if(this.labelxs > 0){
9732 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9733 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9736 } else if ( this.fieldLabel.length) {
9741 //cls : 'input-group-addon',
9742 html : this.fieldLabel
9760 if (this.disabled) {
9761 input.disabled=true;
9768 * return the real textarea element.
9770 inputEl: function ()
9772 return this.el.select('textarea.form-control',true).first();
9776 * Clear any invalid styles/messages for this field
9778 clearInvalid : function()
9781 if(!this.el || this.preventMark){ // not rendered
9785 var label = this.el.select('label', true).first();
9786 var icon = this.el.select('i.fa-star', true).first();
9792 this.el.removeClass(this.invalidClass);
9794 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9796 var feedback = this.el.select('.form-control-feedback', true).first();
9799 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9804 this.fireEvent('valid', this);
9808 * Mark this field as valid
9810 markValid : function()
9812 if(!this.el || this.preventMark){ // not rendered
9816 this.el.removeClass([this.invalidClass, this.validClass]);
9818 var feedback = this.el.select('.form-control-feedback', true).first();
9821 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9824 if(this.disabled || this.allowBlank){
9828 var label = this.el.select('label', true).first();
9829 var icon = this.el.select('i.fa-star', true).first();
9835 this.el.addClass(this.validClass);
9837 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9839 var feedback = this.el.select('.form-control-feedback', true).first();
9842 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9843 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9848 this.fireEvent('valid', this);
9852 * Mark this field as invalid
9853 * @param {String} msg The validation message
9855 markInvalid : function(msg)
9857 if(!this.el || this.preventMark){ // not rendered
9861 this.el.removeClass([this.invalidClass, this.validClass]);
9863 var feedback = this.el.select('.form-control-feedback', true).first();
9866 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9869 if(this.disabled || this.allowBlank){
9873 var label = this.el.select('label', true).first();
9874 var icon = this.el.select('i.fa-star', true).first();
9876 if(!this.getValue().length && label && !icon){
9877 this.el.createChild({
9879 cls : 'text-danger fa fa-lg fa-star',
9880 tooltip : 'This field is required',
9881 style : 'margin-right:5px;'
9885 this.el.addClass(this.invalidClass);
9887 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9889 var feedback = this.el.select('.form-control-feedback', true).first();
9892 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9894 if(this.getValue().length || this.forceFeedback){
9895 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9902 this.fireEvent('invalid', this, msg);
9910 * trigger field - base class for combo..
9915 * @class Roo.bootstrap.TriggerField
9916 * @extends Roo.bootstrap.Input
9917 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9918 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9919 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9920 * for which you can provide a custom implementation. For example:
9922 var trigger = new Roo.bootstrap.TriggerField();
9923 trigger.onTriggerClick = myTriggerFn;
9924 trigger.applyTo('my-field');
9927 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9928 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9929 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9930 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9931 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9934 * Create a new TriggerField.
9935 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9936 * to the base TextField)
9938 Roo.bootstrap.TriggerField = function(config){
9939 this.mimicing = false;
9940 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9943 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9945 * @cfg {String} triggerClass A CSS class to apply to the trigger
9948 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9953 * @cfg {Boolean} removable (true|false) special filter default false
9957 /** @cfg {Boolean} grow @hide */
9958 /** @cfg {Number} growMin @hide */
9959 /** @cfg {Number} growMax @hide */
9965 autoSize: Roo.emptyFn,
9972 actionMode : 'wrap',
9977 getAutoCreate : function(){
9979 var align = this.labelAlign || this.parentLabelAlign();
9984 cls: 'form-group' //input-group
9991 type : this.inputType,
9992 cls : 'form-control',
9993 autocomplete: 'new-password',
9994 placeholder : this.placeholder || ''
9998 input.name = this.name;
10001 input.cls += ' input-' + this.size;
10004 if (this.disabled) {
10005 input.disabled=true;
10008 var inputblock = input;
10010 if(this.hasFeedback && !this.allowBlank){
10014 cls: 'glyphicon form-control-feedback'
10017 if(this.removable && !this.editable && !this.tickable){
10019 cls : 'has-feedback',
10025 cls : 'roo-combo-removable-btn close'
10032 cls : 'has-feedback',
10041 if(this.removable && !this.editable && !this.tickable){
10043 cls : 'roo-removable',
10049 cls : 'roo-combo-removable-btn close'
10056 if (this.before || this.after) {
10059 cls : 'input-group',
10063 inputblock.cn.push({
10065 cls : 'input-group-addon',
10070 inputblock.cn.push(input);
10072 if(this.hasFeedback && !this.allowBlank){
10073 inputblock.cls += ' has-feedback';
10074 inputblock.cn.push(feedback);
10078 inputblock.cn.push({
10080 cls : 'input-group-addon',
10093 cls: 'form-hidden-field'
10107 cls: 'form-hidden-field'
10111 cls: 'roo-select2-choices',
10115 cls: 'roo-select2-search-field',
10128 cls: 'roo-select2-container input-group',
10133 // cls: 'typeahead typeahead-long dropdown-menu',
10134 // style: 'display:none'
10139 if(!this.multiple && this.showToggleBtn){
10145 if (this.caret != false) {
10148 cls: 'fa fa-' + this.caret
10155 cls : 'input-group-addon btn dropdown-toggle',
10160 cls: 'combobox-clear',
10174 combobox.cls += ' roo-select2-container-multi';
10177 if (align ==='left' && this.fieldLabel.length) {
10179 cfg.cls += ' roo-form-group-label-left';
10184 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10185 tooltip : 'This field is required'
10190 cls : 'control-label',
10191 html : this.fieldLabel
10203 var labelCfg = cfg.cn[1];
10204 var contentCfg = cfg.cn[2];
10206 if(this.indicatorpos == 'right'){
10211 cls : 'control-label',
10215 html : this.fieldLabel
10219 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10220 tooltip : 'This field is required'
10233 labelCfg = cfg.cn[0];
10234 contentCfg = cfg.cn[1];
10237 if(this.labelWidth > 12){
10238 labelCfg.style = "width: " + this.labelWidth + 'px';
10241 if(this.labelWidth < 13 && this.labelmd == 0){
10242 this.labelmd = this.labelWidth;
10245 if(this.labellg > 0){
10246 labelCfg.cls += ' col-lg-' + this.labellg;
10247 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10250 if(this.labelmd > 0){
10251 labelCfg.cls += ' col-md-' + this.labelmd;
10252 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10255 if(this.labelsm > 0){
10256 labelCfg.cls += ' col-sm-' + this.labelsm;
10257 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10260 if(this.labelxs > 0){
10261 labelCfg.cls += ' col-xs-' + this.labelxs;
10262 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10265 } else if ( this.fieldLabel.length) {
10266 // Roo.log(" label");
10270 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10271 tooltip : 'This field is required'
10275 //cls : 'input-group-addon',
10276 html : this.fieldLabel
10284 if(this.indicatorpos == 'right'){
10292 html : this.fieldLabel
10296 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10297 tooltip : 'This field is required'
10310 // Roo.log(" no label && no align");
10317 ['xs','sm','md','lg'].map(function(size){
10318 if (settings[size]) {
10319 cfg.cls += ' col-' + size + '-' + settings[size];
10330 onResize : function(w, h){
10331 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10332 // if(typeof w == 'number'){
10333 // var x = w - this.trigger.getWidth();
10334 // this.inputEl().setWidth(this.adjustWidth('input', x));
10335 // this.trigger.setStyle('left', x+'px');
10340 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10343 getResizeEl : function(){
10344 return this.inputEl();
10348 getPositionEl : function(){
10349 return this.inputEl();
10353 alignErrorIcon : function(){
10354 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10358 initEvents : function(){
10362 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10363 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10364 if(!this.multiple && this.showToggleBtn){
10365 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10366 if(this.hideTrigger){
10367 this.trigger.setDisplayed(false);
10369 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10373 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10376 if(this.removable && !this.editable && !this.tickable){
10377 var close = this.closeTriggerEl();
10380 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10381 close.on('click', this.removeBtnClick, this, close);
10385 //this.trigger.addClassOnOver('x-form-trigger-over');
10386 //this.trigger.addClassOnClick('x-form-trigger-click');
10389 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10393 closeTriggerEl : function()
10395 var close = this.el.select('.roo-combo-removable-btn', true).first();
10396 return close ? close : false;
10399 removeBtnClick : function(e, h, el)
10401 e.preventDefault();
10403 if(this.fireEvent("remove", this) !== false){
10405 this.fireEvent("afterremove", this)
10409 createList : function()
10411 this.list = Roo.get(document.body).createChild({
10413 cls: 'typeahead typeahead-long dropdown-menu',
10414 style: 'display:none'
10417 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10422 initTrigger : function(){
10427 onDestroy : function(){
10429 this.trigger.removeAllListeners();
10430 // this.trigger.remove();
10433 // this.wrap.remove();
10435 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10439 onFocus : function(){
10440 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10442 if(!this.mimicing){
10443 this.wrap.addClass('x-trigger-wrap-focus');
10444 this.mimicing = true;
10445 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10446 if(this.monitorTab){
10447 this.el.on("keydown", this.checkTab, this);
10454 checkTab : function(e){
10455 if(e.getKey() == e.TAB){
10456 this.triggerBlur();
10461 onBlur : function(){
10466 mimicBlur : function(e, t){
10468 if(!this.wrap.contains(t) && this.validateBlur()){
10469 this.triggerBlur();
10475 triggerBlur : function(){
10476 this.mimicing = false;
10477 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10478 if(this.monitorTab){
10479 this.el.un("keydown", this.checkTab, this);
10481 //this.wrap.removeClass('x-trigger-wrap-focus');
10482 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10486 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10487 validateBlur : function(e, t){
10492 onDisable : function(){
10493 this.inputEl().dom.disabled = true;
10494 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10496 // this.wrap.addClass('x-item-disabled');
10501 onEnable : function(){
10502 this.inputEl().dom.disabled = false;
10503 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10505 // this.el.removeClass('x-item-disabled');
10510 onShow : function(){
10511 var ae = this.getActionEl();
10514 ae.dom.style.display = '';
10515 ae.dom.style.visibility = 'visible';
10521 onHide : function(){
10522 var ae = this.getActionEl();
10523 ae.dom.style.display = 'none';
10527 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10528 * by an implementing function.
10530 * @param {EventObject} e
10532 onTriggerClick : Roo.emptyFn
10536 * Ext JS Library 1.1.1
10537 * Copyright(c) 2006-2007, Ext JS, LLC.
10539 * Originally Released Under LGPL - original licence link has changed is not relivant.
10542 * <script type="text/javascript">
10547 * @class Roo.data.SortTypes
10549 * Defines the default sorting (casting?) comparison functions used when sorting data.
10551 Roo.data.SortTypes = {
10553 * Default sort that does nothing
10554 * @param {Mixed} s The value being converted
10555 * @return {Mixed} The comparison value
10557 none : function(s){
10562 * The regular expression used to strip tags
10566 stripTagsRE : /<\/?[^>]+>/gi,
10569 * Strips all HTML tags to sort on text only
10570 * @param {Mixed} s The value being converted
10571 * @return {String} The comparison value
10573 asText : function(s){
10574 return String(s).replace(this.stripTagsRE, "");
10578 * Strips all HTML tags to sort on text only - Case insensitive
10579 * @param {Mixed} s The value being converted
10580 * @return {String} The comparison value
10582 asUCText : function(s){
10583 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10587 * Case insensitive string
10588 * @param {Mixed} s The value being converted
10589 * @return {String} The comparison value
10591 asUCString : function(s) {
10592 return String(s).toUpperCase();
10597 * @param {Mixed} s The value being converted
10598 * @return {Number} The comparison value
10600 asDate : function(s) {
10604 if(s instanceof Date){
10605 return s.getTime();
10607 return Date.parse(String(s));
10612 * @param {Mixed} s The value being converted
10613 * @return {Float} The comparison value
10615 asFloat : function(s) {
10616 var val = parseFloat(String(s).replace(/,/g, ""));
10625 * @param {Mixed} s The value being converted
10626 * @return {Number} The comparison value
10628 asInt : function(s) {
10629 var val = parseInt(String(s).replace(/,/g, ""));
10637 * Ext JS Library 1.1.1
10638 * Copyright(c) 2006-2007, Ext JS, LLC.
10640 * Originally Released Under LGPL - original licence link has changed is not relivant.
10643 * <script type="text/javascript">
10647 * @class Roo.data.Record
10648 * Instances of this class encapsulate both record <em>definition</em> information, and record
10649 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10650 * to access Records cached in an {@link Roo.data.Store} object.<br>
10652 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10653 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10656 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10658 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10659 * {@link #create}. The parameters are the same.
10660 * @param {Array} data An associative Array of data values keyed by the field name.
10661 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10662 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10663 * not specified an integer id is generated.
10665 Roo.data.Record = function(data, id){
10666 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10671 * Generate a constructor for a specific record layout.
10672 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10673 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10674 * Each field definition object may contain the following properties: <ul>
10675 * <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,
10676 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10677 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10678 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10679 * is being used, then this is a string containing the javascript expression to reference the data relative to
10680 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10681 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10682 * this may be omitted.</p></li>
10683 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10684 * <ul><li>auto (Default, implies no conversion)</li>
10689 * <li>date</li></ul></p></li>
10690 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10691 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10692 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10693 * by the Reader into an object that will be stored in the Record. It is passed the
10694 * following parameters:<ul>
10695 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10697 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10699 * <br>usage:<br><pre><code>
10700 var TopicRecord = Roo.data.Record.create(
10701 {name: 'title', mapping: 'topic_title'},
10702 {name: 'author', mapping: 'username'},
10703 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10704 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10705 {name: 'lastPoster', mapping: 'user2'},
10706 {name: 'excerpt', mapping: 'post_text'}
10709 var myNewRecord = new TopicRecord({
10710 title: 'Do my job please',
10713 lastPost: new Date(),
10714 lastPoster: 'Animal',
10715 excerpt: 'No way dude!'
10717 myStore.add(myNewRecord);
10722 Roo.data.Record.create = function(o){
10723 var f = function(){
10724 f.superclass.constructor.apply(this, arguments);
10726 Roo.extend(f, Roo.data.Record);
10727 var p = f.prototype;
10728 p.fields = new Roo.util.MixedCollection(false, function(field){
10731 for(var i = 0, len = o.length; i < len; i++){
10732 p.fields.add(new Roo.data.Field(o[i]));
10734 f.getField = function(name){
10735 return p.fields.get(name);
10740 Roo.data.Record.AUTO_ID = 1000;
10741 Roo.data.Record.EDIT = 'edit';
10742 Roo.data.Record.REJECT = 'reject';
10743 Roo.data.Record.COMMIT = 'commit';
10745 Roo.data.Record.prototype = {
10747 * Readonly flag - true if this record has been modified.
10756 join : function(store){
10757 this.store = store;
10761 * Set the named field to the specified value.
10762 * @param {String} name The name of the field to set.
10763 * @param {Object} value The value to set the field to.
10765 set : function(name, value){
10766 if(this.data[name] == value){
10770 if(!this.modified){
10771 this.modified = {};
10773 if(typeof this.modified[name] == 'undefined'){
10774 this.modified[name] = this.data[name];
10776 this.data[name] = value;
10777 if(!this.editing && this.store){
10778 this.store.afterEdit(this);
10783 * Get the value of the named field.
10784 * @param {String} name The name of the field to get the value of.
10785 * @return {Object} The value of the field.
10787 get : function(name){
10788 return this.data[name];
10792 beginEdit : function(){
10793 this.editing = true;
10794 this.modified = {};
10798 cancelEdit : function(){
10799 this.editing = false;
10800 delete this.modified;
10804 endEdit : function(){
10805 this.editing = false;
10806 if(this.dirty && this.store){
10807 this.store.afterEdit(this);
10812 * Usually called by the {@link Roo.data.Store} which owns the Record.
10813 * Rejects all changes made to the Record since either creation, or the last commit operation.
10814 * Modified fields are reverted to their original values.
10816 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10817 * of reject operations.
10819 reject : function(){
10820 var m = this.modified;
10822 if(typeof m[n] != "function"){
10823 this.data[n] = m[n];
10826 this.dirty = false;
10827 delete this.modified;
10828 this.editing = false;
10830 this.store.afterReject(this);
10835 * Usually called by the {@link Roo.data.Store} which owns the Record.
10836 * Commits all changes made to the Record since either creation, or the last commit operation.
10838 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10839 * of commit operations.
10841 commit : function(){
10842 this.dirty = false;
10843 delete this.modified;
10844 this.editing = false;
10846 this.store.afterCommit(this);
10851 hasError : function(){
10852 return this.error != null;
10856 clearError : function(){
10861 * Creates a copy of this record.
10862 * @param {String} id (optional) A new record id if you don't want to use this record's id
10865 copy : function(newId) {
10866 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10870 * Ext JS Library 1.1.1
10871 * Copyright(c) 2006-2007, Ext JS, LLC.
10873 * Originally Released Under LGPL - original licence link has changed is not relivant.
10876 * <script type="text/javascript">
10882 * @class Roo.data.Store
10883 * @extends Roo.util.Observable
10884 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10885 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10887 * 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
10888 * has no knowledge of the format of the data returned by the Proxy.<br>
10890 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10891 * instances from the data object. These records are cached and made available through accessor functions.
10893 * Creates a new Store.
10894 * @param {Object} config A config object containing the objects needed for the Store to access data,
10895 * and read the data into Records.
10897 Roo.data.Store = function(config){
10898 this.data = new Roo.util.MixedCollection(false);
10899 this.data.getKey = function(o){
10902 this.baseParams = {};
10904 this.paramNames = {
10909 "multisort" : "_multisort"
10912 if(config && config.data){
10913 this.inlineData = config.data;
10914 delete config.data;
10917 Roo.apply(this, config);
10919 if(this.reader){ // reader passed
10920 this.reader = Roo.factory(this.reader, Roo.data);
10921 this.reader.xmodule = this.xmodule || false;
10922 if(!this.recordType){
10923 this.recordType = this.reader.recordType;
10925 if(this.reader.onMetaChange){
10926 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10930 if(this.recordType){
10931 this.fields = this.recordType.prototype.fields;
10933 this.modified = [];
10937 * @event datachanged
10938 * Fires when the data cache has changed, and a widget which is using this Store
10939 * as a Record cache should refresh its view.
10940 * @param {Store} this
10942 datachanged : true,
10944 * @event metachange
10945 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10946 * @param {Store} this
10947 * @param {Object} meta The JSON metadata
10952 * Fires when Records have been added to the Store
10953 * @param {Store} this
10954 * @param {Roo.data.Record[]} records The array of Records added
10955 * @param {Number} index The index at which the record(s) were added
10960 * Fires when a Record has been removed from the Store
10961 * @param {Store} this
10962 * @param {Roo.data.Record} record The Record that was removed
10963 * @param {Number} index The index at which the record was removed
10968 * Fires when a Record has been updated
10969 * @param {Store} this
10970 * @param {Roo.data.Record} record The Record that was updated
10971 * @param {String} operation The update operation being performed. Value may be one of:
10973 Roo.data.Record.EDIT
10974 Roo.data.Record.REJECT
10975 Roo.data.Record.COMMIT
10981 * Fires when the data cache has been cleared.
10982 * @param {Store} this
10986 * @event beforeload
10987 * Fires before a request is made for a new data object. If the beforeload handler returns false
10988 * the load action will be canceled.
10989 * @param {Store} this
10990 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10994 * @event beforeloadadd
10995 * Fires after a new set of Records has been loaded.
10996 * @param {Store} this
10997 * @param {Roo.data.Record[]} records The Records that were loaded
10998 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11000 beforeloadadd : true,
11003 * Fires after a new set of Records has been loaded, before they are added to the store.
11004 * @param {Store} this
11005 * @param {Roo.data.Record[]} records The Records that were loaded
11006 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11007 * @params {Object} return from reader
11011 * @event loadexception
11012 * Fires if an exception occurs in the Proxy during loading.
11013 * Called with the signature of the Proxy's "loadexception" event.
11014 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11017 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11018 * @param {Object} load options
11019 * @param {Object} jsonData from your request (normally this contains the Exception)
11021 loadexception : true
11025 this.proxy = Roo.factory(this.proxy, Roo.data);
11026 this.proxy.xmodule = this.xmodule || false;
11027 this.relayEvents(this.proxy, ["loadexception"]);
11029 this.sortToggle = {};
11030 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11032 Roo.data.Store.superclass.constructor.call(this);
11034 if(this.inlineData){
11035 this.loadData(this.inlineData);
11036 delete this.inlineData;
11040 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11042 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11043 * without a remote query - used by combo/forms at present.
11047 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11050 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11053 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11054 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11057 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11058 * on any HTTP request
11061 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11064 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11068 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11069 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11071 remoteSort : false,
11074 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11075 * loaded or when a record is removed. (defaults to false).
11077 pruneModifiedRecords : false,
11080 lastOptions : null,
11083 * Add Records to the Store and fires the add event.
11084 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11086 add : function(records){
11087 records = [].concat(records);
11088 for(var i = 0, len = records.length; i < len; i++){
11089 records[i].join(this);
11091 var index = this.data.length;
11092 this.data.addAll(records);
11093 this.fireEvent("add", this, records, index);
11097 * Remove a Record from the Store and fires the remove event.
11098 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11100 remove : function(record){
11101 var index = this.data.indexOf(record);
11102 this.data.removeAt(index);
11103 if(this.pruneModifiedRecords){
11104 this.modified.remove(record);
11106 this.fireEvent("remove", this, record, index);
11110 * Remove all Records from the Store and fires the clear event.
11112 removeAll : function(){
11114 if(this.pruneModifiedRecords){
11115 this.modified = [];
11117 this.fireEvent("clear", this);
11121 * Inserts Records to the Store at the given index and fires the add event.
11122 * @param {Number} index The start index at which to insert the passed Records.
11123 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11125 insert : function(index, records){
11126 records = [].concat(records);
11127 for(var i = 0, len = records.length; i < len; i++){
11128 this.data.insert(index, records[i]);
11129 records[i].join(this);
11131 this.fireEvent("add", this, records, index);
11135 * Get the index within the cache of the passed Record.
11136 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11137 * @return {Number} The index of the passed Record. Returns -1 if not found.
11139 indexOf : function(record){
11140 return this.data.indexOf(record);
11144 * Get the index within the cache of the Record with the passed id.
11145 * @param {String} id The id of the Record to find.
11146 * @return {Number} The index of the Record. Returns -1 if not found.
11148 indexOfId : function(id){
11149 return this.data.indexOfKey(id);
11153 * Get the Record with the specified id.
11154 * @param {String} id The id of the Record to find.
11155 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11157 getById : function(id){
11158 return this.data.key(id);
11162 * Get the Record at the specified index.
11163 * @param {Number} index The index of the Record to find.
11164 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11166 getAt : function(index){
11167 return this.data.itemAt(index);
11171 * Returns a range of Records between specified indices.
11172 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11173 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11174 * @return {Roo.data.Record[]} An array of Records
11176 getRange : function(start, end){
11177 return this.data.getRange(start, end);
11181 storeOptions : function(o){
11182 o = Roo.apply({}, o);
11185 this.lastOptions = o;
11189 * Loads the Record cache from the configured Proxy using the configured Reader.
11191 * If using remote paging, then the first load call must specify the <em>start</em>
11192 * and <em>limit</em> properties in the options.params property to establish the initial
11193 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11195 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11196 * and this call will return before the new data has been loaded. Perform any post-processing
11197 * in a callback function, or in a "load" event handler.</strong>
11199 * @param {Object} options An object containing properties which control loading options:<ul>
11200 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11201 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11202 * passed the following arguments:<ul>
11203 * <li>r : Roo.data.Record[]</li>
11204 * <li>options: Options object from the load call</li>
11205 * <li>success: Boolean success indicator</li></ul></li>
11206 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11207 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11210 load : function(options){
11211 options = options || {};
11212 if(this.fireEvent("beforeload", this, options) !== false){
11213 this.storeOptions(options);
11214 var p = Roo.apply(options.params || {}, this.baseParams);
11215 // if meta was not loaded from remote source.. try requesting it.
11216 if (!this.reader.metaFromRemote) {
11217 p._requestMeta = 1;
11219 if(this.sortInfo && this.remoteSort){
11220 var pn = this.paramNames;
11221 p[pn["sort"]] = this.sortInfo.field;
11222 p[pn["dir"]] = this.sortInfo.direction;
11224 if (this.multiSort) {
11225 var pn = this.paramNames;
11226 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11229 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11234 * Reloads the Record cache from the configured Proxy using the configured Reader and
11235 * the options from the last load operation performed.
11236 * @param {Object} options (optional) An object containing properties which may override the options
11237 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11238 * the most recently used options are reused).
11240 reload : function(options){
11241 this.load(Roo.applyIf(options||{}, this.lastOptions));
11245 // Called as a callback by the Reader during a load operation.
11246 loadRecords : function(o, options, success){
11247 if(!o || success === false){
11248 if(success !== false){
11249 this.fireEvent("load", this, [], options, o);
11251 if(options.callback){
11252 options.callback.call(options.scope || this, [], options, false);
11256 // if data returned failure - throw an exception.
11257 if (o.success === false) {
11258 // show a message if no listener is registered.
11259 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11260 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11262 // loadmask wil be hooked into this..
11263 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11266 var r = o.records, t = o.totalRecords || r.length;
11268 this.fireEvent("beforeloadadd", this, r, options, o);
11270 if(!options || options.add !== true){
11271 if(this.pruneModifiedRecords){
11272 this.modified = [];
11274 for(var i = 0, len = r.length; i < len; i++){
11278 this.data = this.snapshot;
11279 delete this.snapshot;
11282 this.data.addAll(r);
11283 this.totalLength = t;
11285 this.fireEvent("datachanged", this);
11287 this.totalLength = Math.max(t, this.data.length+r.length);
11291 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11293 var e = new Roo.data.Record({});
11295 e.set(this.parent.displayField, this.parent.emptyTitle);
11296 e.set(this.parent.valueField, '');
11301 this.fireEvent("load", this, r, options, o);
11302 if(options.callback){
11303 options.callback.call(options.scope || this, r, options, true);
11309 * Loads data from a passed data block. A Reader which understands the format of the data
11310 * must have been configured in the constructor.
11311 * @param {Object} data The data block from which to read the Records. The format of the data expected
11312 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11313 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11315 loadData : function(o, append){
11316 var r = this.reader.readRecords(o);
11317 this.loadRecords(r, {add: append}, true);
11321 * Gets the number of cached records.
11323 * <em>If using paging, this may not be the total size of the dataset. If the data object
11324 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11325 * the data set size</em>
11327 getCount : function(){
11328 return this.data.length || 0;
11332 * Gets the total number of records in the dataset as returned by the server.
11334 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11335 * the dataset size</em>
11337 getTotalCount : function(){
11338 return this.totalLength || 0;
11342 * Returns the sort state of the Store as an object with two properties:
11344 field {String} The name of the field by which the Records are sorted
11345 direction {String} The sort order, "ASC" or "DESC"
11348 getSortState : function(){
11349 return this.sortInfo;
11353 applySort : function(){
11354 if(this.sortInfo && !this.remoteSort){
11355 var s = this.sortInfo, f = s.field;
11356 var st = this.fields.get(f).sortType;
11357 var fn = function(r1, r2){
11358 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11359 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11361 this.data.sort(s.direction, fn);
11362 if(this.snapshot && this.snapshot != this.data){
11363 this.snapshot.sort(s.direction, fn);
11369 * Sets the default sort column and order to be used by the next load operation.
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 setDefaultSort : function(field, dir){
11374 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11378 * Sort the Records.
11379 * If remote sorting is used, the sort is performed on the server, and the cache is
11380 * reloaded. If local sorting is used, the cache is sorted internally.
11381 * @param {String} fieldName The name of the field to sort by.
11382 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11384 sort : function(fieldName, dir){
11385 var f = this.fields.get(fieldName);
11387 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11389 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11390 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11395 this.sortToggle[f.name] = dir;
11396 this.sortInfo = {field: f.name, direction: dir};
11397 if(!this.remoteSort){
11399 this.fireEvent("datachanged", this);
11401 this.load(this.lastOptions);
11406 * Calls the specified function for each of the Records in the cache.
11407 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11408 * Returning <em>false</em> aborts and exits the iteration.
11409 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11411 each : function(fn, scope){
11412 this.data.each(fn, scope);
11416 * Gets all records modified since the last commit. Modified records are persisted across load operations
11417 * (e.g., during paging).
11418 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11420 getModifiedRecords : function(){
11421 return this.modified;
11425 createFilterFn : function(property, value, anyMatch){
11426 if(!value.exec){ // not a regex
11427 value = String(value);
11428 if(value.length == 0){
11431 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11433 return function(r){
11434 return value.test(r.data[property]);
11439 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11440 * @param {String} property A field on your records
11441 * @param {Number} start The record index to start at (defaults to 0)
11442 * @param {Number} end The last record index to include (defaults to length - 1)
11443 * @return {Number} The sum
11445 sum : function(property, start, end){
11446 var rs = this.data.items, v = 0;
11447 start = start || 0;
11448 end = (end || end === 0) ? end : rs.length-1;
11450 for(var i = start; i <= end; i++){
11451 v += (rs[i].data[property] || 0);
11457 * Filter the records by a specified property.
11458 * @param {String} field A field on your records
11459 * @param {String/RegExp} value Either a string that the field
11460 * should start with or a RegExp to test against the field
11461 * @param {Boolean} anyMatch True to match any part not just the beginning
11463 filter : function(property, value, anyMatch){
11464 var fn = this.createFilterFn(property, value, anyMatch);
11465 return fn ? this.filterBy(fn) : this.clearFilter();
11469 * Filter by a function. The specified function will be called with each
11470 * record in this data source. If the function returns true the record is included,
11471 * otherwise it is filtered.
11472 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11473 * @param {Object} scope (optional) The scope of the function (defaults to this)
11475 filterBy : function(fn, scope){
11476 this.snapshot = this.snapshot || this.data;
11477 this.data = this.queryBy(fn, scope||this);
11478 this.fireEvent("datachanged", this);
11482 * Query the records by a specified property.
11483 * @param {String} field A field on your records
11484 * @param {String/RegExp} value Either a string that the field
11485 * should start with or a RegExp to test against the field
11486 * @param {Boolean} anyMatch True to match any part not just the beginning
11487 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11489 query : function(property, value, anyMatch){
11490 var fn = this.createFilterFn(property, value, anyMatch);
11491 return fn ? this.queryBy(fn) : this.data.clone();
11495 * Query by a function. The specified function will be called with each
11496 * record in this data source. If the function returns true the record is included
11498 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11499 * @param {Object} scope (optional) The scope of the function (defaults to this)
11500 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11502 queryBy : function(fn, scope){
11503 var data = this.snapshot || this.data;
11504 return data.filterBy(fn, scope||this);
11508 * Collects unique values for a particular dataIndex from this store.
11509 * @param {String} dataIndex The property to collect
11510 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11511 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11512 * @return {Array} An array of the unique values
11514 collect : function(dataIndex, allowNull, bypassFilter){
11515 var d = (bypassFilter === true && this.snapshot) ?
11516 this.snapshot.items : this.data.items;
11517 var v, sv, r = [], l = {};
11518 for(var i = 0, len = d.length; i < len; i++){
11519 v = d[i].data[dataIndex];
11521 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11530 * Revert to a view of the Record cache with no filtering applied.
11531 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11533 clearFilter : function(suppressEvent){
11534 if(this.snapshot && this.snapshot != this.data){
11535 this.data = this.snapshot;
11536 delete this.snapshot;
11537 if(suppressEvent !== true){
11538 this.fireEvent("datachanged", this);
11544 afterEdit : function(record){
11545 if(this.modified.indexOf(record) == -1){
11546 this.modified.push(record);
11548 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11552 afterReject : function(record){
11553 this.modified.remove(record);
11554 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11558 afterCommit : function(record){
11559 this.modified.remove(record);
11560 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11564 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11565 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11567 commitChanges : function(){
11568 var m = this.modified.slice(0);
11569 this.modified = [];
11570 for(var i = 0, len = m.length; i < len; i++){
11576 * Cancel outstanding changes on all changed records.
11578 rejectChanges : function(){
11579 var m = this.modified.slice(0);
11580 this.modified = [];
11581 for(var i = 0, len = m.length; i < len; i++){
11586 onMetaChange : function(meta, rtype, o){
11587 this.recordType = rtype;
11588 this.fields = rtype.prototype.fields;
11589 delete this.snapshot;
11590 this.sortInfo = meta.sortInfo || this.sortInfo;
11591 this.modified = [];
11592 this.fireEvent('metachange', this, this.reader.meta);
11595 moveIndex : function(data, type)
11597 var index = this.indexOf(data);
11599 var newIndex = index + type;
11603 this.insert(newIndex, data);
11608 * Ext JS Library 1.1.1
11609 * Copyright(c) 2006-2007, Ext JS, LLC.
11611 * Originally Released Under LGPL - original licence link has changed is not relivant.
11614 * <script type="text/javascript">
11618 * @class Roo.data.SimpleStore
11619 * @extends Roo.data.Store
11620 * Small helper class to make creating Stores from Array data easier.
11621 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11622 * @cfg {Array} fields An array of field definition objects, or field name strings.
11623 * @cfg {Array} data The multi-dimensional array of data
11625 * @param {Object} config
11627 Roo.data.SimpleStore = function(config){
11628 Roo.data.SimpleStore.superclass.constructor.call(this, {
11630 reader: new Roo.data.ArrayReader({
11633 Roo.data.Record.create(config.fields)
11635 proxy : new Roo.data.MemoryProxy(config.data)
11639 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11641 * Ext JS Library 1.1.1
11642 * Copyright(c) 2006-2007, Ext JS, LLC.
11644 * Originally Released Under LGPL - original licence link has changed is not relivant.
11647 * <script type="text/javascript">
11652 * @extends Roo.data.Store
11653 * @class Roo.data.JsonStore
11654 * Small helper class to make creating Stores for JSON data easier. <br/>
11656 var store = new Roo.data.JsonStore({
11657 url: 'get-images.php',
11659 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11662 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11663 * JsonReader and HttpProxy (unless inline data is provided).</b>
11664 * @cfg {Array} fields An array of field definition objects, or field name strings.
11666 * @param {Object} config
11668 Roo.data.JsonStore = function(c){
11669 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11670 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11671 reader: new Roo.data.JsonReader(c, c.fields)
11674 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11676 * Ext JS Library 1.1.1
11677 * Copyright(c) 2006-2007, Ext JS, LLC.
11679 * Originally Released Under LGPL - original licence link has changed is not relivant.
11682 * <script type="text/javascript">
11686 Roo.data.Field = function(config){
11687 if(typeof config == "string"){
11688 config = {name: config};
11690 Roo.apply(this, config);
11693 this.type = "auto";
11696 var st = Roo.data.SortTypes;
11697 // named sortTypes are supported, here we look them up
11698 if(typeof this.sortType == "string"){
11699 this.sortType = st[this.sortType];
11702 // set default sortType for strings and dates
11703 if(!this.sortType){
11706 this.sortType = st.asUCString;
11709 this.sortType = st.asDate;
11712 this.sortType = st.none;
11717 var stripRe = /[\$,%]/g;
11719 // prebuilt conversion function for this field, instead of
11720 // switching every time we're reading a value
11722 var cv, dateFormat = this.dateFormat;
11727 cv = function(v){ return v; };
11730 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11734 return v !== undefined && v !== null && v !== '' ?
11735 parseInt(String(v).replace(stripRe, ""), 10) : '';
11740 return v !== undefined && v !== null && v !== '' ?
11741 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11746 cv = function(v){ return v === true || v === "true" || v == 1; };
11753 if(v instanceof Date){
11757 if(dateFormat == "timestamp"){
11758 return new Date(v*1000);
11760 return Date.parseDate(v, dateFormat);
11762 var parsed = Date.parse(v);
11763 return parsed ? new Date(parsed) : null;
11772 Roo.data.Field.prototype = {
11780 * Ext JS Library 1.1.1
11781 * Copyright(c) 2006-2007, Ext JS, LLC.
11783 * Originally Released Under LGPL - original licence link has changed is not relivant.
11786 * <script type="text/javascript">
11789 // Base class for reading structured data from a data source. This class is intended to be
11790 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11793 * @class Roo.data.DataReader
11794 * Base class for reading structured data from a data source. This class is intended to be
11795 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11798 Roo.data.DataReader = function(meta, recordType){
11802 this.recordType = recordType instanceof Array ?
11803 Roo.data.Record.create(recordType) : recordType;
11806 Roo.data.DataReader.prototype = {
11808 * Create an empty record
11809 * @param {Object} data (optional) - overlay some values
11810 * @return {Roo.data.Record} record created.
11812 newRow : function(d) {
11814 this.recordType.prototype.fields.each(function(c) {
11816 case 'int' : da[c.name] = 0; break;
11817 case 'date' : da[c.name] = new Date(); break;
11818 case 'float' : da[c.name] = 0.0; break;
11819 case 'boolean' : da[c.name] = false; break;
11820 default : da[c.name] = ""; break;
11824 return new this.recordType(Roo.apply(da, d));
11829 * Ext JS Library 1.1.1
11830 * Copyright(c) 2006-2007, Ext JS, LLC.
11832 * Originally Released Under LGPL - original licence link has changed is not relivant.
11835 * <script type="text/javascript">
11839 * @class Roo.data.DataProxy
11840 * @extends Roo.data.Observable
11841 * This class is an abstract base class for implementations which provide retrieval of
11842 * unformatted data objects.<br>
11844 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11845 * (of the appropriate type which knows how to parse the data object) to provide a block of
11846 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11848 * Custom implementations must implement the load method as described in
11849 * {@link Roo.data.HttpProxy#load}.
11851 Roo.data.DataProxy = function(){
11854 * @event beforeload
11855 * Fires before a network request is made to retrieve a data object.
11856 * @param {Object} This DataProxy object.
11857 * @param {Object} params The params parameter to the load function.
11862 * Fires before the load method's callback is called.
11863 * @param {Object} This DataProxy object.
11864 * @param {Object} o The data object.
11865 * @param {Object} arg The callback argument object passed to the load function.
11869 * @event loadexception
11870 * Fires if an Exception occurs during data retrieval.
11871 * @param {Object} This DataProxy object.
11872 * @param {Object} o The data object.
11873 * @param {Object} arg The callback argument object passed to the load function.
11874 * @param {Object} e The Exception.
11876 loadexception : true
11878 Roo.data.DataProxy.superclass.constructor.call(this);
11881 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11884 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11888 * Ext JS Library 1.1.1
11889 * Copyright(c) 2006-2007, Ext JS, LLC.
11891 * Originally Released Under LGPL - original licence link has changed is not relivant.
11894 * <script type="text/javascript">
11897 * @class Roo.data.MemoryProxy
11898 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11899 * to the Reader when its load method is called.
11901 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11903 Roo.data.MemoryProxy = function(data){
11907 Roo.data.MemoryProxy.superclass.constructor.call(this);
11911 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11914 * Load data from the requested source (in this case an in-memory
11915 * data object passed to the constructor), read the data object into
11916 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11917 * process that block using the passed callback.
11918 * @param {Object} params This parameter is not used by the MemoryProxy class.
11919 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11920 * object into a block of Roo.data.Records.
11921 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11922 * The function must be passed <ul>
11923 * <li>The Record block object</li>
11924 * <li>The "arg" argument from the load function</li>
11925 * <li>A boolean success indicator</li>
11927 * @param {Object} scope The scope in which to call the callback
11928 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11930 load : function(params, reader, callback, scope, arg){
11931 params = params || {};
11934 result = reader.readRecords(this.data);
11936 this.fireEvent("loadexception", this, arg, null, e);
11937 callback.call(scope, null, arg, false);
11940 callback.call(scope, result, arg, true);
11944 update : function(params, records){
11949 * Ext JS Library 1.1.1
11950 * Copyright(c) 2006-2007, Ext JS, LLC.
11952 * Originally Released Under LGPL - original licence link has changed is not relivant.
11955 * <script type="text/javascript">
11958 * @class Roo.data.HttpProxy
11959 * @extends Roo.data.DataProxy
11960 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11961 * configured to reference a certain URL.<br><br>
11963 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11964 * from which the running page was served.<br><br>
11966 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11968 * Be aware that to enable the browser to parse an XML document, the server must set
11969 * the Content-Type header in the HTTP response to "text/xml".
11971 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11972 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11973 * will be used to make the request.
11975 Roo.data.HttpProxy = function(conn){
11976 Roo.data.HttpProxy.superclass.constructor.call(this);
11977 // is conn a conn config or a real conn?
11979 this.useAjax = !conn || !conn.events;
11983 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11984 // thse are take from connection...
11987 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11990 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11991 * extra parameters to each request made by this object. (defaults to undefined)
11994 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11995 * to each request made by this object. (defaults to undefined)
11998 * @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)
12001 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12004 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12010 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12014 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12015 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12016 * a finer-grained basis than the DataProxy events.
12018 getConnection : function(){
12019 return this.useAjax ? Roo.Ajax : this.conn;
12023 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12024 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12025 * process that block using the passed callback.
12026 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12027 * for the request to the remote server.
12028 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12029 * object into a block of Roo.data.Records.
12030 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12031 * The function must be passed <ul>
12032 * <li>The Record block object</li>
12033 * <li>The "arg" argument from the load function</li>
12034 * <li>A boolean success indicator</li>
12036 * @param {Object} scope The scope in which to call the callback
12037 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12039 load : function(params, reader, callback, scope, arg){
12040 if(this.fireEvent("beforeload", this, params) !== false){
12042 params : params || {},
12044 callback : callback,
12049 callback : this.loadResponse,
12053 Roo.applyIf(o, this.conn);
12054 if(this.activeRequest){
12055 Roo.Ajax.abort(this.activeRequest);
12057 this.activeRequest = Roo.Ajax.request(o);
12059 this.conn.request(o);
12062 callback.call(scope||this, null, arg, false);
12067 loadResponse : function(o, success, response){
12068 delete this.activeRequest;
12070 this.fireEvent("loadexception", this, o, response);
12071 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12076 result = o.reader.read(response);
12078 this.fireEvent("loadexception", this, o, response, e);
12079 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12083 this.fireEvent("load", this, o, o.request.arg);
12084 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12088 update : function(dataSet){
12093 updateResponse : function(dataSet){
12098 * Ext JS Library 1.1.1
12099 * Copyright(c) 2006-2007, Ext JS, LLC.
12101 * Originally Released Under LGPL - original licence link has changed is not relivant.
12104 * <script type="text/javascript">
12108 * @class Roo.data.ScriptTagProxy
12109 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12110 * other than the originating domain of the running page.<br><br>
12112 * <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
12113 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12115 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12116 * source code that is used as the source inside a <script> tag.<br><br>
12118 * In order for the browser to process the returned data, the server must wrap the data object
12119 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12120 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12121 * depending on whether the callback name was passed:
12124 boolean scriptTag = false;
12125 String cb = request.getParameter("callback");
12128 response.setContentType("text/javascript");
12130 response.setContentType("application/x-json");
12132 Writer out = response.getWriter();
12134 out.write(cb + "(");
12136 out.print(dataBlock.toJsonString());
12143 * @param {Object} config A configuration object.
12145 Roo.data.ScriptTagProxy = function(config){
12146 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12147 Roo.apply(this, config);
12148 this.head = document.getElementsByTagName("head")[0];
12151 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12153 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12155 * @cfg {String} url The URL from which to request the data object.
12158 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12162 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12163 * the server the name of the callback function set up by the load call to process the returned data object.
12164 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12165 * javascript output which calls this named function passing the data object as its only parameter.
12167 callbackParam : "callback",
12169 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12170 * name to the request.
12175 * Load data from the configured URL, read the data object into
12176 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12177 * process that block using the passed callback.
12178 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12179 * for the request to the remote server.
12180 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12181 * object into a block of Roo.data.Records.
12182 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12183 * The function must be passed <ul>
12184 * <li>The Record block object</li>
12185 * <li>The "arg" argument from the load function</li>
12186 * <li>A boolean success indicator</li>
12188 * @param {Object} scope The scope in which to call the callback
12189 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12191 load : function(params, reader, callback, scope, arg){
12192 if(this.fireEvent("beforeload", this, params) !== false){
12194 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12196 var url = this.url;
12197 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12199 url += "&_dc=" + (new Date().getTime());
12201 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12204 cb : "stcCallback"+transId,
12205 scriptId : "stcScript"+transId,
12209 callback : callback,
12215 window[trans.cb] = function(o){
12216 conn.handleResponse(o, trans);
12219 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12221 if(this.autoAbort !== false){
12225 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12227 var script = document.createElement("script");
12228 script.setAttribute("src", url);
12229 script.setAttribute("type", "text/javascript");
12230 script.setAttribute("id", trans.scriptId);
12231 this.head.appendChild(script);
12233 this.trans = trans;
12235 callback.call(scope||this, null, arg, false);
12240 isLoading : function(){
12241 return this.trans ? true : false;
12245 * Abort the current server request.
12247 abort : function(){
12248 if(this.isLoading()){
12249 this.destroyTrans(this.trans);
12254 destroyTrans : function(trans, isLoaded){
12255 this.head.removeChild(document.getElementById(trans.scriptId));
12256 clearTimeout(trans.timeoutId);
12258 window[trans.cb] = undefined;
12260 delete window[trans.cb];
12263 // if hasn't been loaded, wait for load to remove it to prevent script error
12264 window[trans.cb] = function(){
12265 window[trans.cb] = undefined;
12267 delete window[trans.cb];
12274 handleResponse : function(o, trans){
12275 this.trans = false;
12276 this.destroyTrans(trans, true);
12279 result = trans.reader.readRecords(o);
12281 this.fireEvent("loadexception", this, o, trans.arg, e);
12282 trans.callback.call(trans.scope||window, null, trans.arg, false);
12285 this.fireEvent("load", this, o, trans.arg);
12286 trans.callback.call(trans.scope||window, result, trans.arg, true);
12290 handleFailure : function(trans){
12291 this.trans = false;
12292 this.destroyTrans(trans, false);
12293 this.fireEvent("loadexception", this, null, trans.arg);
12294 trans.callback.call(trans.scope||window, null, trans.arg, false);
12298 * Ext JS Library 1.1.1
12299 * Copyright(c) 2006-2007, Ext JS, LLC.
12301 * Originally Released Under LGPL - original licence link has changed is not relivant.
12304 * <script type="text/javascript">
12308 * @class Roo.data.JsonReader
12309 * @extends Roo.data.DataReader
12310 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12311 * based on mappings in a provided Roo.data.Record constructor.
12313 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12314 * in the reply previously.
12319 var RecordDef = Roo.data.Record.create([
12320 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12321 {name: 'occupation'} // This field will use "occupation" as the mapping.
12323 var myReader = new Roo.data.JsonReader({
12324 totalProperty: "results", // The property which contains the total dataset size (optional)
12325 root: "rows", // The property which contains an Array of row objects
12326 id: "id" // The property within each row object that provides an ID for the record (optional)
12330 * This would consume a JSON file like this:
12332 { 'results': 2, 'rows': [
12333 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12334 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12337 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12338 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12339 * paged from the remote server.
12340 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12341 * @cfg {String} root name of the property which contains the Array of row objects.
12342 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12343 * @cfg {Array} fields Array of field definition objects
12345 * Create a new JsonReader
12346 * @param {Object} meta Metadata configuration options
12347 * @param {Object} recordType Either an Array of field definition objects,
12348 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12350 Roo.data.JsonReader = function(meta, recordType){
12353 // set some defaults:
12354 Roo.applyIf(meta, {
12355 totalProperty: 'total',
12356 successProperty : 'success',
12361 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12363 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12366 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12367 * Used by Store query builder to append _requestMeta to params.
12370 metaFromRemote : false,
12372 * This method is only used by a DataProxy which has retrieved data from a remote server.
12373 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12374 * @return {Object} data A data block which is used by an Roo.data.Store object as
12375 * a cache of Roo.data.Records.
12377 read : function(response){
12378 var json = response.responseText;
12380 var o = /* eval:var:o */ eval("("+json+")");
12382 throw {message: "JsonReader.read: Json object not found"};
12388 this.metaFromRemote = true;
12389 this.meta = o.metaData;
12390 this.recordType = Roo.data.Record.create(o.metaData.fields);
12391 this.onMetaChange(this.meta, this.recordType, o);
12393 return this.readRecords(o);
12396 // private function a store will implement
12397 onMetaChange : function(meta, recordType, o){
12404 simpleAccess: function(obj, subsc) {
12411 getJsonAccessor: function(){
12413 return function(expr) {
12415 return(re.test(expr))
12416 ? new Function("obj", "return obj." + expr)
12421 return Roo.emptyFn;
12426 * Create a data block containing Roo.data.Records from an XML document.
12427 * @param {Object} o An object which contains an Array of row objects in the property specified
12428 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12429 * which contains the total size of the dataset.
12430 * @return {Object} data A data block which is used by an Roo.data.Store object as
12431 * a cache of Roo.data.Records.
12433 readRecords : function(o){
12435 * After any data loads, the raw JSON data is available for further custom processing.
12439 var s = this.meta, Record = this.recordType,
12440 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12442 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12444 if(s.totalProperty) {
12445 this.getTotal = this.getJsonAccessor(s.totalProperty);
12447 if(s.successProperty) {
12448 this.getSuccess = this.getJsonAccessor(s.successProperty);
12450 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12452 var g = this.getJsonAccessor(s.id);
12453 this.getId = function(rec) {
12455 return (r === undefined || r === "") ? null : r;
12458 this.getId = function(){return null;};
12461 for(var jj = 0; jj < fl; jj++){
12463 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12464 this.ef[jj] = this.getJsonAccessor(map);
12468 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12469 if(s.totalProperty){
12470 var vt = parseInt(this.getTotal(o), 10);
12475 if(s.successProperty){
12476 var vs = this.getSuccess(o);
12477 if(vs === false || vs === 'false'){
12482 for(var i = 0; i < c; i++){
12485 var id = this.getId(n);
12486 for(var j = 0; j < fl; j++){
12488 var v = this.ef[j](n);
12490 Roo.log('missing convert for ' + f.name);
12494 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12496 var record = new Record(values, id);
12498 records[i] = record;
12504 totalRecords : totalRecords
12509 * Ext JS Library 1.1.1
12510 * Copyright(c) 2006-2007, Ext JS, LLC.
12512 * Originally Released Under LGPL - original licence link has changed is not relivant.
12515 * <script type="text/javascript">
12519 * @class Roo.data.ArrayReader
12520 * @extends Roo.data.DataReader
12521 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12522 * Each element of that Array represents a row of data fields. The
12523 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12524 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12528 var RecordDef = Roo.data.Record.create([
12529 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12530 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12532 var myReader = new Roo.data.ArrayReader({
12533 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12537 * This would consume an Array like this:
12539 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12541 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12543 * Create a new JsonReader
12544 * @param {Object} meta Metadata configuration options.
12545 * @param {Object} recordType Either an Array of field definition objects
12546 * as specified to {@link Roo.data.Record#create},
12547 * or an {@link Roo.data.Record} object
12548 * created using {@link Roo.data.Record#create}.
12550 Roo.data.ArrayReader = function(meta, recordType){
12551 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12554 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12556 * Create a data block containing Roo.data.Records from an XML document.
12557 * @param {Object} o An Array of row objects which represents the dataset.
12558 * @return {Object} data A data block which is used by an Roo.data.Store object as
12559 * a cache of Roo.data.Records.
12561 readRecords : function(o){
12562 var sid = this.meta ? this.meta.id : null;
12563 var recordType = this.recordType, fields = recordType.prototype.fields;
12566 for(var i = 0; i < root.length; i++){
12569 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12570 for(var j = 0, jlen = fields.length; j < jlen; j++){
12571 var f = fields.items[j];
12572 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12573 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12575 values[f.name] = v;
12577 var record = new recordType(values, id);
12579 records[records.length] = record;
12583 totalRecords : records.length
12592 * @class Roo.bootstrap.ComboBox
12593 * @extends Roo.bootstrap.TriggerField
12594 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12595 * @cfg {Boolean} append (true|false) default false
12596 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12597 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12598 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12599 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12600 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12601 * @cfg {Boolean} animate default true
12602 * @cfg {Boolean} emptyResultText only for touch device
12603 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12604 * @cfg {String} emptyTitle default ''
12606 * Create a new ComboBox.
12607 * @param {Object} config Configuration options
12609 Roo.bootstrap.ComboBox = function(config){
12610 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12614 * Fires when the dropdown list is expanded
12615 * @param {Roo.bootstrap.ComboBox} combo This combo box
12620 * Fires when the dropdown list is collapsed
12621 * @param {Roo.bootstrap.ComboBox} combo This combo box
12625 * @event beforeselect
12626 * Fires before a list item is selected. Return false to cancel the selection.
12627 * @param {Roo.bootstrap.ComboBox} combo This combo box
12628 * @param {Roo.data.Record} record The data record returned from the underlying store
12629 * @param {Number} index The index of the selected item in the dropdown list
12631 'beforeselect' : true,
12634 * Fires when a list item is selected
12635 * @param {Roo.bootstrap.ComboBox} combo This combo box
12636 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12637 * @param {Number} index The index of the selected item in the dropdown list
12641 * @event beforequery
12642 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12643 * The event object passed has these properties:
12644 * @param {Roo.bootstrap.ComboBox} combo This combo box
12645 * @param {String} query The query
12646 * @param {Boolean} forceAll true to force "all" query
12647 * @param {Boolean} cancel true to cancel the query
12648 * @param {Object} e The query event object
12650 'beforequery': true,
12653 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12654 * @param {Roo.bootstrap.ComboBox} combo This combo box
12659 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12660 * @param {Roo.bootstrap.ComboBox} combo This combo box
12661 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12666 * Fires when the remove value from the combobox array
12667 * @param {Roo.bootstrap.ComboBox} combo This combo box
12671 * @event afterremove
12672 * Fires when the remove value from the combobox array
12673 * @param {Roo.bootstrap.ComboBox} combo This combo box
12675 'afterremove' : true,
12677 * @event specialfilter
12678 * Fires when specialfilter
12679 * @param {Roo.bootstrap.ComboBox} combo This combo box
12681 'specialfilter' : true,
12684 * Fires when tick the element
12685 * @param {Roo.bootstrap.ComboBox} combo This combo box
12689 * @event touchviewdisplay
12690 * Fires when touch view require special display (default is using displayField)
12691 * @param {Roo.bootstrap.ComboBox} combo This combo box
12692 * @param {Object} cfg set html .
12694 'touchviewdisplay' : true
12699 this.tickItems = [];
12701 this.selectedIndex = -1;
12702 if(this.mode == 'local'){
12703 if(config.queryDelay === undefined){
12704 this.queryDelay = 10;
12706 if(config.minChars === undefined){
12712 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12715 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12716 * rendering into an Roo.Editor, defaults to false)
12719 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12720 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12723 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12726 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12727 * the dropdown list (defaults to undefined, with no header element)
12731 * @cfg {String/Roo.Template} tpl The template to use to render the output
12735 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12737 listWidth: undefined,
12739 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12740 * mode = 'remote' or 'text' if mode = 'local')
12742 displayField: undefined,
12745 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12746 * mode = 'remote' or 'value' if mode = 'local').
12747 * Note: use of a valueField requires the user make a selection
12748 * in order for a value to be mapped.
12750 valueField: undefined,
12752 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12757 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12758 * field's data value (defaults to the underlying DOM element's name)
12760 hiddenName: undefined,
12762 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12766 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12768 selectedClass: 'active',
12771 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12775 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12776 * anchor positions (defaults to 'tl-bl')
12778 listAlign: 'tl-bl?',
12780 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12784 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12785 * query specified by the allQuery config option (defaults to 'query')
12787 triggerAction: 'query',
12789 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12790 * (defaults to 4, does not apply if editable = false)
12794 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12795 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12799 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12800 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12804 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12805 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12809 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12810 * when editable = true (defaults to false)
12812 selectOnFocus:false,
12814 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12816 queryParam: 'query',
12818 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12819 * when mode = 'remote' (defaults to 'Loading...')
12821 loadingText: 'Loading...',
12823 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12827 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12831 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12832 * traditional select (defaults to true)
12836 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12840 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12844 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12845 * listWidth has a higher value)
12849 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12850 * allow the user to set arbitrary text into the field (defaults to false)
12852 forceSelection:false,
12854 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12855 * if typeAhead = true (defaults to 250)
12857 typeAheadDelay : 250,
12859 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12860 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12862 valueNotFoundText : undefined,
12864 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12866 blockFocus : false,
12869 * @cfg {Boolean} disableClear Disable showing of clear button.
12871 disableClear : false,
12873 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12875 alwaysQuery : false,
12878 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12883 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12885 invalidClass : "has-warning",
12888 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12890 validClass : "has-success",
12893 * @cfg {Boolean} specialFilter (true|false) special filter default false
12895 specialFilter : false,
12898 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12900 mobileTouchView : true,
12903 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12905 useNativeIOS : false,
12907 ios_options : false,
12919 btnPosition : 'right',
12920 triggerList : true,
12921 showToggleBtn : true,
12923 emptyResultText: 'Empty',
12924 triggerText : 'Select',
12927 // element that contains real text value.. (when hidden is used..)
12929 getAutoCreate : function()
12934 * Render classic select for iso
12937 if(Roo.isIOS && this.useNativeIOS){
12938 cfg = this.getAutoCreateNativeIOS();
12946 if(Roo.isTouch && this.mobileTouchView){
12947 cfg = this.getAutoCreateTouchView();
12954 if(!this.tickable){
12955 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12960 * ComboBox with tickable selections
12963 var align = this.labelAlign || this.parentLabelAlign();
12966 cls : 'form-group roo-combobox-tickable' //input-group
12969 var btn_text_select = '';
12970 var btn_text_done = '';
12971 var btn_text_cancel = '';
12973 if (this.btn_text_show) {
12974 btn_text_select = 'Select';
12975 btn_text_done = 'Done';
12976 btn_text_cancel = 'Cancel';
12981 cls : 'tickable-buttons',
12986 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12987 //html : this.triggerText
12988 html: btn_text_select
12994 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12996 html: btn_text_done
13002 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13004 html: btn_text_cancel
13010 buttons.cn.unshift({
13012 cls: 'roo-select2-search-field-input'
13018 Roo.each(buttons.cn, function(c){
13020 c.cls += ' btn-' + _this.size;
13023 if (_this.disabled) {
13034 cls: 'form-hidden-field'
13038 cls: 'roo-select2-choices',
13042 cls: 'roo-select2-search-field',
13053 cls: 'roo-select2-container input-group roo-select2-container-multi',
13058 // cls: 'typeahead typeahead-long dropdown-menu',
13059 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13064 if(this.hasFeedback && !this.allowBlank){
13068 cls: 'glyphicon form-control-feedback'
13071 combobox.cn.push(feedback);
13075 if (align ==='left' && this.fieldLabel.length) {
13077 cfg.cls += ' roo-form-group-label-left';
13082 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13083 tooltip : 'This field is required'
13088 cls : 'control-label',
13089 html : this.fieldLabel
13101 var labelCfg = cfg.cn[1];
13102 var contentCfg = cfg.cn[2];
13105 if(this.indicatorpos == 'right'){
13111 cls : 'control-label',
13115 html : this.fieldLabel
13119 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13120 tooltip : 'This field is required'
13135 labelCfg = cfg.cn[0];
13136 contentCfg = cfg.cn[1];
13140 if(this.labelWidth > 12){
13141 labelCfg.style = "width: " + this.labelWidth + 'px';
13144 if(this.labelWidth < 13 && this.labelmd == 0){
13145 this.labelmd = this.labelWidth;
13148 if(this.labellg > 0){
13149 labelCfg.cls += ' col-lg-' + this.labellg;
13150 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13153 if(this.labelmd > 0){
13154 labelCfg.cls += ' col-md-' + this.labelmd;
13155 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13158 if(this.labelsm > 0){
13159 labelCfg.cls += ' col-sm-' + this.labelsm;
13160 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13163 if(this.labelxs > 0){
13164 labelCfg.cls += ' col-xs-' + this.labelxs;
13165 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13169 } else if ( this.fieldLabel.length) {
13170 // Roo.log(" label");
13174 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13175 tooltip : 'This field is required'
13179 //cls : 'input-group-addon',
13180 html : this.fieldLabel
13185 if(this.indicatorpos == 'right'){
13189 //cls : 'input-group-addon',
13190 html : this.fieldLabel
13194 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13195 tooltip : 'This field is required'
13204 // Roo.log(" no label && no align");
13211 ['xs','sm','md','lg'].map(function(size){
13212 if (settings[size]) {
13213 cfg.cls += ' col-' + size + '-' + settings[size];
13221 _initEventsCalled : false,
13224 initEvents: function()
13226 if (this._initEventsCalled) { // as we call render... prevent looping...
13229 this._initEventsCalled = true;
13232 throw "can not find store for combo";
13235 this.indicator = this.indicatorEl();
13237 this.store = Roo.factory(this.store, Roo.data);
13238 this.store.parent = this;
13240 // if we are building from html. then this element is so complex, that we can not really
13241 // use the rendered HTML.
13242 // so we have to trash and replace the previous code.
13243 if (Roo.XComponent.build_from_html) {
13244 // remove this element....
13245 var e = this.el.dom, k=0;
13246 while (e ) { e = e.previousSibling; ++k;}
13251 this.rendered = false;
13253 this.render(this.parent().getChildContainer(true), k);
13256 if(Roo.isIOS && this.useNativeIOS){
13257 this.initIOSView();
13265 if(Roo.isTouch && this.mobileTouchView){
13266 this.initTouchView();
13271 this.initTickableEvents();
13275 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13277 if(this.hiddenName){
13279 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13281 this.hiddenField.dom.value =
13282 this.hiddenValue !== undefined ? this.hiddenValue :
13283 this.value !== undefined ? this.value : '';
13285 // prevent input submission
13286 this.el.dom.removeAttribute('name');
13287 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13292 // this.el.dom.setAttribute('autocomplete', 'off');
13295 var cls = 'x-combo-list';
13297 //this.list = new Roo.Layer({
13298 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13304 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13305 _this.list.setWidth(lw);
13308 this.list.on('mouseover', this.onViewOver, this);
13309 this.list.on('mousemove', this.onViewMove, this);
13310 this.list.on('scroll', this.onViewScroll, this);
13313 this.list.swallowEvent('mousewheel');
13314 this.assetHeight = 0;
13317 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13318 this.assetHeight += this.header.getHeight();
13321 this.innerList = this.list.createChild({cls:cls+'-inner'});
13322 this.innerList.on('mouseover', this.onViewOver, this);
13323 this.innerList.on('mousemove', this.onViewMove, this);
13324 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13326 if(this.allowBlank && !this.pageSize && !this.disableClear){
13327 this.footer = this.list.createChild({cls:cls+'-ft'});
13328 this.pageTb = new Roo.Toolbar(this.footer);
13332 this.footer = this.list.createChild({cls:cls+'-ft'});
13333 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13334 {pageSize: this.pageSize});
13338 if (this.pageTb && this.allowBlank && !this.disableClear) {
13340 this.pageTb.add(new Roo.Toolbar.Fill(), {
13341 cls: 'x-btn-icon x-btn-clear',
13343 handler: function()
13346 _this.clearValue();
13347 _this.onSelect(false, -1);
13352 this.assetHeight += this.footer.getHeight();
13357 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13360 this.view = new Roo.View(this.list, this.tpl, {
13361 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13363 //this.view.wrapEl.setDisplayed(false);
13364 this.view.on('click', this.onViewClick, this);
13367 this.store.on('beforeload', this.onBeforeLoad, this);
13368 this.store.on('load', this.onLoad, this);
13369 this.store.on('loadexception', this.onLoadException, this);
13371 if(this.resizable){
13372 this.resizer = new Roo.Resizable(this.list, {
13373 pinned:true, handles:'se'
13375 this.resizer.on('resize', function(r, w, h){
13376 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13377 this.listWidth = w;
13378 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13379 this.restrictHeight();
13381 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13384 if(!this.editable){
13385 this.editable = true;
13386 this.setEditable(false);
13391 if (typeof(this.events.add.listeners) != 'undefined') {
13393 this.addicon = this.wrap.createChild(
13394 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13396 this.addicon.on('click', function(e) {
13397 this.fireEvent('add', this);
13400 if (typeof(this.events.edit.listeners) != 'undefined') {
13402 this.editicon = this.wrap.createChild(
13403 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13404 if (this.addicon) {
13405 this.editicon.setStyle('margin-left', '40px');
13407 this.editicon.on('click', function(e) {
13409 // we fire even if inothing is selected..
13410 this.fireEvent('edit', this, this.lastData );
13416 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13417 "up" : function(e){
13418 this.inKeyMode = true;
13422 "down" : function(e){
13423 if(!this.isExpanded()){
13424 this.onTriggerClick();
13426 this.inKeyMode = true;
13431 "enter" : function(e){
13432 // this.onViewClick();
13436 if(this.fireEvent("specialkey", this, e)){
13437 this.onViewClick(false);
13443 "esc" : function(e){
13447 "tab" : function(e){
13450 if(this.fireEvent("specialkey", this, e)){
13451 this.onViewClick(false);
13459 doRelay : function(foo, bar, hname){
13460 if(hname == 'down' || this.scope.isExpanded()){
13461 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13470 this.queryDelay = Math.max(this.queryDelay || 10,
13471 this.mode == 'local' ? 10 : 250);
13474 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13476 if(this.typeAhead){
13477 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13479 if(this.editable !== false){
13480 this.inputEl().on("keyup", this.onKeyUp, this);
13482 if(this.forceSelection){
13483 this.inputEl().on('blur', this.doForce, this);
13487 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13488 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13492 initTickableEvents: function()
13496 if(this.hiddenName){
13498 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13500 this.hiddenField.dom.value =
13501 this.hiddenValue !== undefined ? this.hiddenValue :
13502 this.value !== undefined ? this.value : '';
13504 // prevent input submission
13505 this.el.dom.removeAttribute('name');
13506 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13511 // this.list = this.el.select('ul.dropdown-menu',true).first();
13513 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13514 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13515 if(this.triggerList){
13516 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13519 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13520 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13522 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13523 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13525 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13526 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13528 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13529 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13530 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13533 this.cancelBtn.hide();
13538 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13539 _this.list.setWidth(lw);
13542 this.list.on('mouseover', this.onViewOver, this);
13543 this.list.on('mousemove', this.onViewMove, this);
13545 this.list.on('scroll', this.onViewScroll, this);
13548 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>';
13551 this.view = new Roo.View(this.list, this.tpl, {
13552 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13555 //this.view.wrapEl.setDisplayed(false);
13556 this.view.on('click', this.onViewClick, this);
13560 this.store.on('beforeload', this.onBeforeLoad, this);
13561 this.store.on('load', this.onLoad, this);
13562 this.store.on('loadexception', this.onLoadException, this);
13565 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13566 "up" : function(e){
13567 this.inKeyMode = true;
13571 "down" : function(e){
13572 this.inKeyMode = true;
13576 "enter" : function(e){
13577 if(this.fireEvent("specialkey", this, e)){
13578 this.onViewClick(false);
13584 "esc" : function(e){
13585 this.onTickableFooterButtonClick(e, false, false);
13588 "tab" : function(e){
13589 this.fireEvent("specialkey", this, e);
13591 this.onTickableFooterButtonClick(e, false, false);
13598 doRelay : function(e, fn, key){
13599 if(this.scope.isExpanded()){
13600 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13609 this.queryDelay = Math.max(this.queryDelay || 10,
13610 this.mode == 'local' ? 10 : 250);
13613 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13615 if(this.typeAhead){
13616 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13619 if(this.editable !== false){
13620 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13623 this.indicator = this.indicatorEl();
13625 if(this.indicator){
13626 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13627 this.indicator.hide();
13632 onDestroy : function(){
13634 this.view.setStore(null);
13635 this.view.el.removeAllListeners();
13636 this.view.el.remove();
13637 this.view.purgeListeners();
13640 this.list.dom.innerHTML = '';
13644 this.store.un('beforeload', this.onBeforeLoad, this);
13645 this.store.un('load', this.onLoad, this);
13646 this.store.un('loadexception', this.onLoadException, this);
13648 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13652 fireKey : function(e){
13653 if(e.isNavKeyPress() && !this.list.isVisible()){
13654 this.fireEvent("specialkey", this, e);
13659 onResize: function(w, h){
13660 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13662 // if(typeof w != 'number'){
13663 // // we do not handle it!?!?
13666 // var tw = this.trigger.getWidth();
13667 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13668 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13670 // this.inputEl().setWidth( this.adjustWidth('input', x));
13672 // //this.trigger.setStyle('left', x+'px');
13674 // if(this.list && this.listWidth === undefined){
13675 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13676 // this.list.setWidth(lw);
13677 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13685 * Allow or prevent the user from directly editing the field text. If false is passed,
13686 * the user will only be able to select from the items defined in the dropdown list. This method
13687 * is the runtime equivalent of setting the 'editable' config option at config time.
13688 * @param {Boolean} value True to allow the user to directly edit the field text
13690 setEditable : function(value){
13691 if(value == this.editable){
13694 this.editable = value;
13696 this.inputEl().dom.setAttribute('readOnly', true);
13697 this.inputEl().on('mousedown', this.onTriggerClick, this);
13698 this.inputEl().addClass('x-combo-noedit');
13700 this.inputEl().dom.setAttribute('readOnly', false);
13701 this.inputEl().un('mousedown', this.onTriggerClick, this);
13702 this.inputEl().removeClass('x-combo-noedit');
13708 onBeforeLoad : function(combo,opts){
13709 if(!this.hasFocus){
13713 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13715 this.restrictHeight();
13716 this.selectedIndex = -1;
13720 onLoad : function(){
13722 this.hasQuery = false;
13724 if(!this.hasFocus){
13728 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13729 this.loading.hide();
13732 if(this.store.getCount() > 0){
13735 this.restrictHeight();
13736 if(this.lastQuery == this.allQuery){
13737 if(this.editable && !this.tickable){
13738 this.inputEl().dom.select();
13742 !this.selectByValue(this.value, true) &&
13745 !this.store.lastOptions ||
13746 typeof(this.store.lastOptions.add) == 'undefined' ||
13747 this.store.lastOptions.add != true
13750 this.select(0, true);
13753 if(this.autoFocus){
13756 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13757 this.taTask.delay(this.typeAheadDelay);
13761 this.onEmptyResults();
13767 onLoadException : function()
13769 this.hasQuery = false;
13771 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13772 this.loading.hide();
13775 if(this.tickable && this.editable){
13780 // only causes errors at present
13781 //Roo.log(this.store.reader.jsonData);
13782 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13784 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13790 onTypeAhead : function(){
13791 if(this.store.getCount() > 0){
13792 var r = this.store.getAt(0);
13793 var newValue = r.data[this.displayField];
13794 var len = newValue.length;
13795 var selStart = this.getRawValue().length;
13797 if(selStart != len){
13798 this.setRawValue(newValue);
13799 this.selectText(selStart, newValue.length);
13805 onSelect : function(record, index){
13807 if(this.fireEvent('beforeselect', this, record, index) !== false){
13809 this.setFromData(index > -1 ? record.data : false);
13812 this.fireEvent('select', this, record, index);
13817 * Returns the currently selected field value or empty string if no value is set.
13818 * @return {String} value The selected value
13820 getValue : function()
13822 if(Roo.isIOS && this.useNativeIOS){
13823 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13827 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13830 if(this.valueField){
13831 return typeof this.value != 'undefined' ? this.value : '';
13833 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13837 getRawValue : function()
13839 if(Roo.isIOS && this.useNativeIOS){
13840 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13843 var v = this.inputEl().getValue();
13849 * Clears any text/value currently set in the field
13851 clearValue : function(){
13853 if(this.hiddenField){
13854 this.hiddenField.dom.value = '';
13857 this.setRawValue('');
13858 this.lastSelectionText = '';
13859 this.lastData = false;
13861 var close = this.closeTriggerEl();
13872 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13873 * will be displayed in the field. If the value does not match the data value of an existing item,
13874 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13875 * Otherwise the field will be blank (although the value will still be set).
13876 * @param {String} value The value to match
13878 setValue : function(v)
13880 if(Roo.isIOS && this.useNativeIOS){
13881 this.setIOSValue(v);
13891 if(this.valueField){
13892 var r = this.findRecord(this.valueField, v);
13894 text = r.data[this.displayField];
13895 }else if(this.valueNotFoundText !== undefined){
13896 text = this.valueNotFoundText;
13899 this.lastSelectionText = text;
13900 if(this.hiddenField){
13901 this.hiddenField.dom.value = v;
13903 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13906 var close = this.closeTriggerEl();
13909 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13915 * @property {Object} the last set data for the element
13920 * Sets the value of the field based on a object which is related to the record format for the store.
13921 * @param {Object} value the value to set as. or false on reset?
13923 setFromData : function(o){
13930 var dv = ''; // display value
13931 var vv = ''; // value value..
13933 if (this.displayField) {
13934 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13936 // this is an error condition!!!
13937 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13940 if(this.valueField){
13941 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13944 var close = this.closeTriggerEl();
13947 if(dv.length || vv * 1 > 0){
13949 this.blockFocus=true;
13955 if(this.hiddenField){
13956 this.hiddenField.dom.value = vv;
13958 this.lastSelectionText = dv;
13959 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13963 // no hidden field.. - we store the value in 'value', but still display
13964 // display field!!!!
13965 this.lastSelectionText = dv;
13966 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13973 reset : function(){
13974 // overridden so that last data is reset..
13981 this.setValue(this.originalValue);
13982 //this.clearInvalid();
13983 this.lastData = false;
13985 this.view.clearSelections();
13991 findRecord : function(prop, value){
13993 if(this.store.getCount() > 0){
13994 this.store.each(function(r){
13995 if(r.data[prop] == value){
14005 getName: function()
14007 // returns hidden if it's set..
14008 if (!this.rendered) {return ''};
14009 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14013 onViewMove : function(e, t){
14014 this.inKeyMode = false;
14018 onViewOver : function(e, t){
14019 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14022 var item = this.view.findItemFromChild(t);
14025 var index = this.view.indexOf(item);
14026 this.select(index, false);
14031 onViewClick : function(view, doFocus, el, e)
14033 var index = this.view.getSelectedIndexes()[0];
14035 var r = this.store.getAt(index);
14039 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14046 Roo.each(this.tickItems, function(v,k){
14048 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14050 _this.tickItems.splice(k, 1);
14052 if(typeof(e) == 'undefined' && view == false){
14053 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14065 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14066 this.tickItems.push(r.data);
14069 if(typeof(e) == 'undefined' && view == false){
14070 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14077 this.onSelect(r, index);
14079 if(doFocus !== false && !this.blockFocus){
14080 this.inputEl().focus();
14085 restrictHeight : function(){
14086 //this.innerList.dom.style.height = '';
14087 //var inner = this.innerList.dom;
14088 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14089 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14090 //this.list.beginUpdate();
14091 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14092 this.list.alignTo(this.inputEl(), this.listAlign);
14093 this.list.alignTo(this.inputEl(), this.listAlign);
14094 //this.list.endUpdate();
14098 onEmptyResults : function(){
14100 if(this.tickable && this.editable){
14101 this.hasFocus = false;
14102 this.restrictHeight();
14110 * Returns true if the dropdown list is expanded, else false.
14112 isExpanded : function(){
14113 return this.list.isVisible();
14117 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14118 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14119 * @param {String} value The data value of the item to select
14120 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14121 * selected item if it is not currently in view (defaults to true)
14122 * @return {Boolean} True if the value matched an item in the list, else false
14124 selectByValue : function(v, scrollIntoView){
14125 if(v !== undefined && v !== null){
14126 var r = this.findRecord(this.valueField || this.displayField, v);
14128 this.select(this.store.indexOf(r), scrollIntoView);
14136 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14137 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14138 * @param {Number} index The zero-based index of the list item to select
14139 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14140 * selected item if it is not currently in view (defaults to true)
14142 select : function(index, scrollIntoView){
14143 this.selectedIndex = index;
14144 this.view.select(index);
14145 if(scrollIntoView !== false){
14146 var el = this.view.getNode(index);
14148 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14151 this.list.scrollChildIntoView(el, false);
14157 selectNext : function(){
14158 var ct = this.store.getCount();
14160 if(this.selectedIndex == -1){
14162 }else if(this.selectedIndex < ct-1){
14163 this.select(this.selectedIndex+1);
14169 selectPrev : function(){
14170 var ct = this.store.getCount();
14172 if(this.selectedIndex == -1){
14174 }else if(this.selectedIndex != 0){
14175 this.select(this.selectedIndex-1);
14181 onKeyUp : function(e){
14182 if(this.editable !== false && !e.isSpecialKey()){
14183 this.lastKey = e.getKey();
14184 this.dqTask.delay(this.queryDelay);
14189 validateBlur : function(){
14190 return !this.list || !this.list.isVisible();
14194 initQuery : function(){
14196 var v = this.getRawValue();
14198 if(this.tickable && this.editable){
14199 v = this.tickableInputEl().getValue();
14206 doForce : function(){
14207 if(this.inputEl().dom.value.length > 0){
14208 this.inputEl().dom.value =
14209 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14215 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14216 * query allowing the query action to be canceled if needed.
14217 * @param {String} query The SQL query to execute
14218 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14219 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14220 * saved in the current store (defaults to false)
14222 doQuery : function(q, forceAll){
14224 if(q === undefined || q === null){
14229 forceAll: forceAll,
14233 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14238 forceAll = qe.forceAll;
14239 if(forceAll === true || (q.length >= this.minChars)){
14241 this.hasQuery = true;
14243 if(this.lastQuery != q || this.alwaysQuery){
14244 this.lastQuery = q;
14245 if(this.mode == 'local'){
14246 this.selectedIndex = -1;
14248 this.store.clearFilter();
14251 if(this.specialFilter){
14252 this.fireEvent('specialfilter', this);
14257 this.store.filter(this.displayField, q);
14260 this.store.fireEvent("datachanged", this.store);
14267 this.store.baseParams[this.queryParam] = q;
14269 var options = {params : this.getParams(q)};
14272 options.add = true;
14273 options.params.start = this.page * this.pageSize;
14276 this.store.load(options);
14279 * this code will make the page width larger, at the beginning, the list not align correctly,
14280 * we should expand the list on onLoad
14281 * so command out it
14286 this.selectedIndex = -1;
14291 this.loadNext = false;
14295 getParams : function(q){
14297 //p[this.queryParam] = q;
14301 p.limit = this.pageSize;
14307 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14309 collapse : function(){
14310 if(!this.isExpanded()){
14316 this.hasFocus = false;
14320 this.cancelBtn.hide();
14321 this.trigger.show();
14324 this.tickableInputEl().dom.value = '';
14325 this.tickableInputEl().blur();
14330 Roo.get(document).un('mousedown', this.collapseIf, this);
14331 Roo.get(document).un('mousewheel', this.collapseIf, this);
14332 if (!this.editable) {
14333 Roo.get(document).un('keydown', this.listKeyPress, this);
14335 this.fireEvent('collapse', this);
14341 collapseIf : function(e){
14342 var in_combo = e.within(this.el);
14343 var in_list = e.within(this.list);
14344 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14346 if (in_combo || in_list || is_list) {
14347 //e.stopPropagation();
14352 this.onTickableFooterButtonClick(e, false, false);
14360 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14362 expand : function(){
14364 if(this.isExpanded() || !this.hasFocus){
14368 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14369 this.list.setWidth(lw);
14375 this.restrictHeight();
14379 this.tickItems = Roo.apply([], this.item);
14382 this.cancelBtn.show();
14383 this.trigger.hide();
14386 this.tickableInputEl().focus();
14391 Roo.get(document).on('mousedown', this.collapseIf, this);
14392 Roo.get(document).on('mousewheel', this.collapseIf, this);
14393 if (!this.editable) {
14394 Roo.get(document).on('keydown', this.listKeyPress, this);
14397 this.fireEvent('expand', this);
14401 // Implements the default empty TriggerField.onTriggerClick function
14402 onTriggerClick : function(e)
14404 Roo.log('trigger click');
14406 if(this.disabled || !this.triggerList){
14411 this.loadNext = false;
14413 if(this.isExpanded()){
14415 if (!this.blockFocus) {
14416 this.inputEl().focus();
14420 this.hasFocus = true;
14421 if(this.triggerAction == 'all') {
14422 this.doQuery(this.allQuery, true);
14424 this.doQuery(this.getRawValue());
14426 if (!this.blockFocus) {
14427 this.inputEl().focus();
14432 onTickableTriggerClick : function(e)
14439 this.loadNext = false;
14440 this.hasFocus = true;
14442 if(this.triggerAction == 'all') {
14443 this.doQuery(this.allQuery, true);
14445 this.doQuery(this.getRawValue());
14449 onSearchFieldClick : function(e)
14451 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14452 this.onTickableFooterButtonClick(e, false, false);
14456 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14461 this.loadNext = false;
14462 this.hasFocus = true;
14464 if(this.triggerAction == 'all') {
14465 this.doQuery(this.allQuery, true);
14467 this.doQuery(this.getRawValue());
14471 listKeyPress : function(e)
14473 //Roo.log('listkeypress');
14474 // scroll to first matching element based on key pres..
14475 if (e.isSpecialKey()) {
14478 var k = String.fromCharCode(e.getKey()).toUpperCase();
14481 var csel = this.view.getSelectedNodes();
14482 var cselitem = false;
14484 var ix = this.view.indexOf(csel[0]);
14485 cselitem = this.store.getAt(ix);
14486 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14492 this.store.each(function(v) {
14494 // start at existing selection.
14495 if (cselitem.id == v.id) {
14501 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14502 match = this.store.indexOf(v);
14508 if (match === false) {
14509 return true; // no more action?
14512 this.view.select(match);
14513 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14514 sn.scrollIntoView(sn.dom.parentNode, false);
14517 onViewScroll : function(e, t){
14519 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){
14523 this.hasQuery = true;
14525 this.loading = this.list.select('.loading', true).first();
14527 if(this.loading === null){
14528 this.list.createChild({
14530 cls: 'loading roo-select2-more-results roo-select2-active',
14531 html: 'Loading more results...'
14534 this.loading = this.list.select('.loading', true).first();
14536 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14538 this.loading.hide();
14541 this.loading.show();
14546 this.loadNext = true;
14548 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14553 addItem : function(o)
14555 var dv = ''; // display value
14557 if (this.displayField) {
14558 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14560 // this is an error condition!!!
14561 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14568 var choice = this.choices.createChild({
14570 cls: 'roo-select2-search-choice',
14579 cls: 'roo-select2-search-choice-close fa fa-times',
14584 }, this.searchField);
14586 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14588 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14596 this.inputEl().dom.value = '';
14601 onRemoveItem : function(e, _self, o)
14603 e.preventDefault();
14605 this.lastItem = Roo.apply([], this.item);
14607 var index = this.item.indexOf(o.data) * 1;
14610 Roo.log('not this item?!');
14614 this.item.splice(index, 1);
14619 this.fireEvent('remove', this, e);
14625 syncValue : function()
14627 if(!this.item.length){
14634 Roo.each(this.item, function(i){
14635 if(_this.valueField){
14636 value.push(i[_this.valueField]);
14643 this.value = value.join(',');
14645 if(this.hiddenField){
14646 this.hiddenField.dom.value = this.value;
14649 this.store.fireEvent("datachanged", this.store);
14654 clearItem : function()
14656 if(!this.multiple){
14662 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14670 if(this.tickable && !Roo.isTouch){
14671 this.view.refresh();
14675 inputEl: function ()
14677 if(Roo.isIOS && this.useNativeIOS){
14678 return this.el.select('select.roo-ios-select', true).first();
14681 if(Roo.isTouch && this.mobileTouchView){
14682 return this.el.select('input.form-control',true).first();
14686 return this.searchField;
14689 return this.el.select('input.form-control',true).first();
14692 onTickableFooterButtonClick : function(e, btn, el)
14694 e.preventDefault();
14696 this.lastItem = Roo.apply([], this.item);
14698 if(btn && btn.name == 'cancel'){
14699 this.tickItems = Roo.apply([], this.item);
14708 Roo.each(this.tickItems, function(o){
14716 validate : function()
14718 if(this.getVisibilityEl().hasClass('hidden')){
14722 var v = this.getRawValue();
14725 v = this.getValue();
14728 if(this.disabled || this.allowBlank || v.length){
14733 this.markInvalid();
14737 tickableInputEl : function()
14739 if(!this.tickable || !this.editable){
14740 return this.inputEl();
14743 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14747 getAutoCreateTouchView : function()
14752 cls: 'form-group' //input-group
14758 type : this.inputType,
14759 cls : 'form-control x-combo-noedit',
14760 autocomplete: 'new-password',
14761 placeholder : this.placeholder || '',
14766 input.name = this.name;
14770 input.cls += ' input-' + this.size;
14773 if (this.disabled) {
14774 input.disabled = true;
14785 inputblock.cls += ' input-group';
14787 inputblock.cn.unshift({
14789 cls : 'input-group-addon',
14794 if(this.removable && !this.multiple){
14795 inputblock.cls += ' roo-removable';
14797 inputblock.cn.push({
14800 cls : 'roo-combo-removable-btn close'
14804 if(this.hasFeedback && !this.allowBlank){
14806 inputblock.cls += ' has-feedback';
14808 inputblock.cn.push({
14810 cls: 'glyphicon form-control-feedback'
14817 inputblock.cls += (this.before) ? '' : ' input-group';
14819 inputblock.cn.push({
14821 cls : 'input-group-addon',
14832 cls: 'form-hidden-field'
14846 cls: 'form-hidden-field'
14850 cls: 'roo-select2-choices',
14854 cls: 'roo-select2-search-field',
14867 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14873 if(!this.multiple && this.showToggleBtn){
14880 if (this.caret != false) {
14883 cls: 'fa fa-' + this.caret
14890 cls : 'input-group-addon btn dropdown-toggle',
14895 cls: 'combobox-clear',
14909 combobox.cls += ' roo-select2-container-multi';
14912 var align = this.labelAlign || this.parentLabelAlign();
14914 if (align ==='left' && this.fieldLabel.length) {
14919 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14920 tooltip : 'This field is required'
14924 cls : 'control-label',
14925 html : this.fieldLabel
14936 var labelCfg = cfg.cn[1];
14937 var contentCfg = cfg.cn[2];
14940 if(this.indicatorpos == 'right'){
14945 cls : 'control-label',
14949 html : this.fieldLabel
14953 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14954 tooltip : 'This field is required'
14967 labelCfg = cfg.cn[0];
14968 contentCfg = cfg.cn[1];
14973 if(this.labelWidth > 12){
14974 labelCfg.style = "width: " + this.labelWidth + 'px';
14977 if(this.labelWidth < 13 && this.labelmd == 0){
14978 this.labelmd = this.labelWidth;
14981 if(this.labellg > 0){
14982 labelCfg.cls += ' col-lg-' + this.labellg;
14983 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14986 if(this.labelmd > 0){
14987 labelCfg.cls += ' col-md-' + this.labelmd;
14988 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14991 if(this.labelsm > 0){
14992 labelCfg.cls += ' col-sm-' + this.labelsm;
14993 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14996 if(this.labelxs > 0){
14997 labelCfg.cls += ' col-xs-' + this.labelxs;
14998 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15002 } else if ( this.fieldLabel.length) {
15006 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15007 tooltip : 'This field is required'
15011 cls : 'control-label',
15012 html : this.fieldLabel
15023 if(this.indicatorpos == 'right'){
15027 cls : 'control-label',
15028 html : this.fieldLabel,
15032 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15033 tooltip : 'This field is required'
15050 var settings = this;
15052 ['xs','sm','md','lg'].map(function(size){
15053 if (settings[size]) {
15054 cfg.cls += ' col-' + size + '-' + settings[size];
15061 initTouchView : function()
15063 this.renderTouchView();
15065 this.touchViewEl.on('scroll', function(){
15066 this.el.dom.scrollTop = 0;
15069 this.originalValue = this.getValue();
15071 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15073 this.inputEl().on("click", this.showTouchView, this);
15074 if (this.triggerEl) {
15075 this.triggerEl.on("click", this.showTouchView, this);
15079 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15080 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15082 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15084 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15085 this.store.on('load', this.onTouchViewLoad, this);
15086 this.store.on('loadexception', this.onTouchViewLoadException, this);
15088 if(this.hiddenName){
15090 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15092 this.hiddenField.dom.value =
15093 this.hiddenValue !== undefined ? this.hiddenValue :
15094 this.value !== undefined ? this.value : '';
15096 this.el.dom.removeAttribute('name');
15097 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15101 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15102 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15105 if(this.removable && !this.multiple){
15106 var close = this.closeTriggerEl();
15108 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15109 close.on('click', this.removeBtnClick, this, close);
15113 * fix the bug in Safari iOS8
15115 this.inputEl().on("focus", function(e){
15116 document.activeElement.blur();
15124 renderTouchView : function()
15126 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15127 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15129 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15130 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15132 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15133 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15134 this.touchViewBodyEl.setStyle('overflow', 'auto');
15136 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15137 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15139 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15140 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15144 showTouchView : function()
15150 this.touchViewHeaderEl.hide();
15152 if(this.modalTitle.length){
15153 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15154 this.touchViewHeaderEl.show();
15157 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15158 this.touchViewEl.show();
15160 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15162 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15163 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15165 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15167 if(this.modalTitle.length){
15168 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15171 this.touchViewBodyEl.setHeight(bodyHeight);
15175 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15177 this.touchViewEl.addClass('in');
15180 this.doTouchViewQuery();
15184 hideTouchView : function()
15186 this.touchViewEl.removeClass('in');
15190 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15192 this.touchViewEl.setStyle('display', 'none');
15197 setTouchViewValue : function()
15204 Roo.each(this.tickItems, function(o){
15209 this.hideTouchView();
15212 doTouchViewQuery : function()
15221 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15225 if(!this.alwaysQuery || this.mode == 'local'){
15226 this.onTouchViewLoad();
15233 onTouchViewBeforeLoad : function(combo,opts)
15239 onTouchViewLoad : function()
15241 if(this.store.getCount() < 1){
15242 this.onTouchViewEmptyResults();
15246 this.clearTouchView();
15248 var rawValue = this.getRawValue();
15250 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15252 this.tickItems = [];
15254 this.store.data.each(function(d, rowIndex){
15255 var row = this.touchViewListGroup.createChild(template);
15257 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15258 row.addClass(d.data.cls);
15261 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15264 html : d.data[this.displayField]
15267 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15268 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15271 row.removeClass('selected');
15272 if(!this.multiple && this.valueField &&
15273 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15276 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15277 row.addClass('selected');
15280 if(this.multiple && this.valueField &&
15281 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15285 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15286 this.tickItems.push(d.data);
15289 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15293 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15295 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15297 if(this.modalTitle.length){
15298 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15301 var listHeight = this.touchViewListGroup.getHeight();
15305 if(firstChecked && listHeight > bodyHeight){
15306 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15311 onTouchViewLoadException : function()
15313 this.hideTouchView();
15316 onTouchViewEmptyResults : function()
15318 this.clearTouchView();
15320 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15322 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15326 clearTouchView : function()
15328 this.touchViewListGroup.dom.innerHTML = '';
15331 onTouchViewClick : function(e, el, o)
15333 e.preventDefault();
15336 var rowIndex = o.rowIndex;
15338 var r = this.store.getAt(rowIndex);
15340 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15342 if(!this.multiple){
15343 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15344 c.dom.removeAttribute('checked');
15347 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15349 this.setFromData(r.data);
15351 var close = this.closeTriggerEl();
15357 this.hideTouchView();
15359 this.fireEvent('select', this, r, rowIndex);
15364 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15365 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15366 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15370 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15371 this.addItem(r.data);
15372 this.tickItems.push(r.data);
15376 getAutoCreateNativeIOS : function()
15379 cls: 'form-group' //input-group,
15384 cls : 'roo-ios-select'
15388 combobox.name = this.name;
15391 if (this.disabled) {
15392 combobox.disabled = true;
15395 var settings = this;
15397 ['xs','sm','md','lg'].map(function(size){
15398 if (settings[size]) {
15399 cfg.cls += ' col-' + size + '-' + settings[size];
15409 initIOSView : function()
15411 this.store.on('load', this.onIOSViewLoad, this);
15416 onIOSViewLoad : function()
15418 if(this.store.getCount() < 1){
15422 this.clearIOSView();
15424 if(this.allowBlank) {
15426 var default_text = '-- SELECT --';
15428 if(this.placeholder.length){
15429 default_text = this.placeholder;
15432 if(this.emptyTitle.length){
15433 default_text += ' - ' + this.emptyTitle + ' -';
15436 var opt = this.inputEl().createChild({
15439 html : default_text
15443 o[this.valueField] = 0;
15444 o[this.displayField] = default_text;
15446 this.ios_options.push({
15453 this.store.data.each(function(d, rowIndex){
15457 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15458 html = d.data[this.displayField];
15463 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15464 value = d.data[this.valueField];
15473 if(this.value == d.data[this.valueField]){
15474 option['selected'] = true;
15477 var opt = this.inputEl().createChild(option);
15479 this.ios_options.push({
15486 this.inputEl().on('change', function(){
15487 this.fireEvent('select', this);
15492 clearIOSView: function()
15494 this.inputEl().dom.innerHTML = '';
15496 this.ios_options = [];
15499 setIOSValue: function(v)
15503 if(!this.ios_options){
15507 Roo.each(this.ios_options, function(opts){
15509 opts.el.dom.removeAttribute('selected');
15511 if(opts.data[this.valueField] != v){
15515 opts.el.dom.setAttribute('selected', true);
15521 * @cfg {Boolean} grow
15525 * @cfg {Number} growMin
15529 * @cfg {Number} growMax
15538 Roo.apply(Roo.bootstrap.ComboBox, {
15542 cls: 'modal-header',
15564 cls: 'list-group-item',
15568 cls: 'roo-combobox-list-group-item-value'
15572 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15586 listItemCheckbox : {
15588 cls: 'list-group-item',
15592 cls: 'roo-combobox-list-group-item-value'
15596 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15612 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15617 cls: 'modal-footer',
15625 cls: 'col-xs-6 text-left',
15628 cls: 'btn btn-danger roo-touch-view-cancel',
15634 cls: 'col-xs-6 text-right',
15637 cls: 'btn btn-success roo-touch-view-ok',
15648 Roo.apply(Roo.bootstrap.ComboBox, {
15650 touchViewTemplate : {
15652 cls: 'modal fade roo-combobox-touch-view',
15656 cls: 'modal-dialog',
15657 style : 'position:fixed', // we have to fix position....
15661 cls: 'modal-content',
15663 Roo.bootstrap.ComboBox.header,
15664 Roo.bootstrap.ComboBox.body,
15665 Roo.bootstrap.ComboBox.footer
15674 * Ext JS Library 1.1.1
15675 * Copyright(c) 2006-2007, Ext JS, LLC.
15677 * Originally Released Under LGPL - original licence link has changed is not relivant.
15680 * <script type="text/javascript">
15685 * @extends Roo.util.Observable
15686 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15687 * This class also supports single and multi selection modes. <br>
15688 * Create a data model bound view:
15690 var store = new Roo.data.Store(...);
15692 var view = new Roo.View({
15694 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15696 singleSelect: true,
15697 selectedClass: "ydataview-selected",
15701 // listen for node click?
15702 view.on("click", function(vw, index, node, e){
15703 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15707 dataModel.load("foobar.xml");
15709 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15711 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15712 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15714 * Note: old style constructor is still suported (container, template, config)
15717 * Create a new View
15718 * @param {Object} config The config object
15721 Roo.View = function(config, depreciated_tpl, depreciated_config){
15723 this.parent = false;
15725 if (typeof(depreciated_tpl) == 'undefined') {
15726 // new way.. - universal constructor.
15727 Roo.apply(this, config);
15728 this.el = Roo.get(this.el);
15731 this.el = Roo.get(config);
15732 this.tpl = depreciated_tpl;
15733 Roo.apply(this, depreciated_config);
15735 this.wrapEl = this.el.wrap().wrap();
15736 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15739 if(typeof(this.tpl) == "string"){
15740 this.tpl = new Roo.Template(this.tpl);
15742 // support xtype ctors..
15743 this.tpl = new Roo.factory(this.tpl, Roo);
15747 this.tpl.compile();
15752 * @event beforeclick
15753 * Fires before a click is processed. Returns false to cancel the default action.
15754 * @param {Roo.View} this
15755 * @param {Number} index The index of the target node
15756 * @param {HTMLElement} node The target node
15757 * @param {Roo.EventObject} e The raw event object
15759 "beforeclick" : true,
15762 * Fires when a template node is clicked.
15763 * @param {Roo.View} this
15764 * @param {Number} index The index of the target node
15765 * @param {HTMLElement} node The target node
15766 * @param {Roo.EventObject} e The raw event object
15771 * Fires when a template node is double clicked.
15772 * @param {Roo.View} this
15773 * @param {Number} index The index of the target node
15774 * @param {HTMLElement} node The target node
15775 * @param {Roo.EventObject} e The raw event object
15779 * @event contextmenu
15780 * Fires when a template node is right clicked.
15781 * @param {Roo.View} this
15782 * @param {Number} index The index of the target node
15783 * @param {HTMLElement} node The target node
15784 * @param {Roo.EventObject} e The raw event object
15786 "contextmenu" : true,
15788 * @event selectionchange
15789 * Fires when the selected nodes change.
15790 * @param {Roo.View} this
15791 * @param {Array} selections Array of the selected nodes
15793 "selectionchange" : true,
15796 * @event beforeselect
15797 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15798 * @param {Roo.View} this
15799 * @param {HTMLElement} node The node to be selected
15800 * @param {Array} selections Array of currently selected nodes
15802 "beforeselect" : true,
15804 * @event preparedata
15805 * Fires on every row to render, to allow you to change the data.
15806 * @param {Roo.View} this
15807 * @param {Object} data to be rendered (change this)
15809 "preparedata" : true
15817 "click": this.onClick,
15818 "dblclick": this.onDblClick,
15819 "contextmenu": this.onContextMenu,
15823 this.selections = [];
15825 this.cmp = new Roo.CompositeElementLite([]);
15827 this.store = Roo.factory(this.store, Roo.data);
15828 this.setStore(this.store, true);
15831 if ( this.footer && this.footer.xtype) {
15833 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15835 this.footer.dataSource = this.store;
15836 this.footer.container = fctr;
15837 this.footer = Roo.factory(this.footer, Roo);
15838 fctr.insertFirst(this.el);
15840 // this is a bit insane - as the paging toolbar seems to detach the el..
15841 // dom.parentNode.parentNode.parentNode
15842 // they get detached?
15846 Roo.View.superclass.constructor.call(this);
15851 Roo.extend(Roo.View, Roo.util.Observable, {
15854 * @cfg {Roo.data.Store} store Data store to load data from.
15859 * @cfg {String|Roo.Element} el The container element.
15864 * @cfg {String|Roo.Template} tpl The template used by this View
15868 * @cfg {String} dataName the named area of the template to use as the data area
15869 * Works with domtemplates roo-name="name"
15873 * @cfg {String} selectedClass The css class to add to selected nodes
15875 selectedClass : "x-view-selected",
15877 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15882 * @cfg {String} text to display on mask (default Loading)
15886 * @cfg {Boolean} multiSelect Allow multiple selection
15888 multiSelect : false,
15890 * @cfg {Boolean} singleSelect Allow single selection
15892 singleSelect: false,
15895 * @cfg {Boolean} toggleSelect - selecting
15897 toggleSelect : false,
15900 * @cfg {Boolean} tickable - selecting
15905 * Returns the element this view is bound to.
15906 * @return {Roo.Element}
15908 getEl : function(){
15909 return this.wrapEl;
15915 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15917 refresh : function(){
15918 //Roo.log('refresh');
15921 // if we are using something like 'domtemplate', then
15922 // the what gets used is:
15923 // t.applySubtemplate(NAME, data, wrapping data..)
15924 // the outer template then get' applied with
15925 // the store 'extra data'
15926 // and the body get's added to the
15927 // roo-name="data" node?
15928 // <span class='roo-tpl-{name}'></span> ?????
15932 this.clearSelections();
15933 this.el.update("");
15935 var records = this.store.getRange();
15936 if(records.length < 1) {
15938 // is this valid?? = should it render a template??
15940 this.el.update(this.emptyText);
15944 if (this.dataName) {
15945 this.el.update(t.apply(this.store.meta)); //????
15946 el = this.el.child('.roo-tpl-' + this.dataName);
15949 for(var i = 0, len = records.length; i < len; i++){
15950 var data = this.prepareData(records[i].data, i, records[i]);
15951 this.fireEvent("preparedata", this, data, i, records[i]);
15953 var d = Roo.apply({}, data);
15956 Roo.apply(d, {'roo-id' : Roo.id()});
15960 Roo.each(this.parent.item, function(item){
15961 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15964 Roo.apply(d, {'roo-data-checked' : 'checked'});
15968 html[html.length] = Roo.util.Format.trim(
15970 t.applySubtemplate(this.dataName, d, this.store.meta) :
15977 el.update(html.join(""));
15978 this.nodes = el.dom.childNodes;
15979 this.updateIndexes(0);
15984 * Function to override to reformat the data that is sent to
15985 * the template for each node.
15986 * DEPRICATED - use the preparedata event handler.
15987 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15988 * a JSON object for an UpdateManager bound view).
15990 prepareData : function(data, index, record)
15992 this.fireEvent("preparedata", this, data, index, record);
15996 onUpdate : function(ds, record){
15997 // Roo.log('on update');
15998 this.clearSelections();
15999 var index = this.store.indexOf(record);
16000 var n = this.nodes[index];
16001 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16002 n.parentNode.removeChild(n);
16003 this.updateIndexes(index, index);
16009 onAdd : function(ds, records, index)
16011 //Roo.log(['on Add', ds, records, index] );
16012 this.clearSelections();
16013 if(this.nodes.length == 0){
16017 var n = this.nodes[index];
16018 for(var i = 0, len = records.length; i < len; i++){
16019 var d = this.prepareData(records[i].data, i, records[i]);
16021 this.tpl.insertBefore(n, d);
16024 this.tpl.append(this.el, d);
16027 this.updateIndexes(index);
16030 onRemove : function(ds, record, index){
16031 // Roo.log('onRemove');
16032 this.clearSelections();
16033 var el = this.dataName ?
16034 this.el.child('.roo-tpl-' + this.dataName) :
16037 el.dom.removeChild(this.nodes[index]);
16038 this.updateIndexes(index);
16042 * Refresh an individual node.
16043 * @param {Number} index
16045 refreshNode : function(index){
16046 this.onUpdate(this.store, this.store.getAt(index));
16049 updateIndexes : function(startIndex, endIndex){
16050 var ns = this.nodes;
16051 startIndex = startIndex || 0;
16052 endIndex = endIndex || ns.length - 1;
16053 for(var i = startIndex; i <= endIndex; i++){
16054 ns[i].nodeIndex = i;
16059 * Changes the data store this view uses and refresh the view.
16060 * @param {Store} store
16062 setStore : function(store, initial){
16063 if(!initial && this.store){
16064 this.store.un("datachanged", this.refresh);
16065 this.store.un("add", this.onAdd);
16066 this.store.un("remove", this.onRemove);
16067 this.store.un("update", this.onUpdate);
16068 this.store.un("clear", this.refresh);
16069 this.store.un("beforeload", this.onBeforeLoad);
16070 this.store.un("load", this.onLoad);
16071 this.store.un("loadexception", this.onLoad);
16075 store.on("datachanged", this.refresh, this);
16076 store.on("add", this.onAdd, this);
16077 store.on("remove", this.onRemove, this);
16078 store.on("update", this.onUpdate, this);
16079 store.on("clear", this.refresh, this);
16080 store.on("beforeload", this.onBeforeLoad, this);
16081 store.on("load", this.onLoad, this);
16082 store.on("loadexception", this.onLoad, this);
16090 * onbeforeLoad - masks the loading area.
16093 onBeforeLoad : function(store,opts)
16095 //Roo.log('onBeforeLoad');
16097 this.el.update("");
16099 this.el.mask(this.mask ? this.mask : "Loading" );
16101 onLoad : function ()
16108 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16109 * @param {HTMLElement} node
16110 * @return {HTMLElement} The template node
16112 findItemFromChild : function(node){
16113 var el = this.dataName ?
16114 this.el.child('.roo-tpl-' + this.dataName,true) :
16117 if(!node || node.parentNode == el){
16120 var p = node.parentNode;
16121 while(p && p != el){
16122 if(p.parentNode == el){
16131 onClick : function(e){
16132 var item = this.findItemFromChild(e.getTarget());
16134 var index = this.indexOf(item);
16135 if(this.onItemClick(item, index, e) !== false){
16136 this.fireEvent("click", this, index, item, e);
16139 this.clearSelections();
16144 onContextMenu : function(e){
16145 var item = this.findItemFromChild(e.getTarget());
16147 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16152 onDblClick : function(e){
16153 var item = this.findItemFromChild(e.getTarget());
16155 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16159 onItemClick : function(item, index, e)
16161 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16164 if (this.toggleSelect) {
16165 var m = this.isSelected(item) ? 'unselect' : 'select';
16168 _t[m](item, true, false);
16171 if(this.multiSelect || this.singleSelect){
16172 if(this.multiSelect && e.shiftKey && this.lastSelection){
16173 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16175 this.select(item, this.multiSelect && e.ctrlKey);
16176 this.lastSelection = item;
16179 if(!this.tickable){
16180 e.preventDefault();
16188 * Get the number of selected nodes.
16191 getSelectionCount : function(){
16192 return this.selections.length;
16196 * Get the currently selected nodes.
16197 * @return {Array} An array of HTMLElements
16199 getSelectedNodes : function(){
16200 return this.selections;
16204 * Get the indexes of the selected nodes.
16207 getSelectedIndexes : function(){
16208 var indexes = [], s = this.selections;
16209 for(var i = 0, len = s.length; i < len; i++){
16210 indexes.push(s[i].nodeIndex);
16216 * Clear all selections
16217 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16219 clearSelections : function(suppressEvent){
16220 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16221 this.cmp.elements = this.selections;
16222 this.cmp.removeClass(this.selectedClass);
16223 this.selections = [];
16224 if(!suppressEvent){
16225 this.fireEvent("selectionchange", this, this.selections);
16231 * Returns true if the passed node is selected
16232 * @param {HTMLElement/Number} node The node or node index
16233 * @return {Boolean}
16235 isSelected : function(node){
16236 var s = this.selections;
16240 node = this.getNode(node);
16241 return s.indexOf(node) !== -1;
16246 * @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
16247 * @param {Boolean} keepExisting (optional) true to keep existing selections
16248 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16250 select : function(nodeInfo, keepExisting, suppressEvent){
16251 if(nodeInfo instanceof Array){
16253 this.clearSelections(true);
16255 for(var i = 0, len = nodeInfo.length; i < len; i++){
16256 this.select(nodeInfo[i], true, true);
16260 var node = this.getNode(nodeInfo);
16261 if(!node || this.isSelected(node)){
16262 return; // already selected.
16265 this.clearSelections(true);
16268 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16269 Roo.fly(node).addClass(this.selectedClass);
16270 this.selections.push(node);
16271 if(!suppressEvent){
16272 this.fireEvent("selectionchange", this, this.selections);
16280 * @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
16281 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16282 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16284 unselect : function(nodeInfo, keepExisting, suppressEvent)
16286 if(nodeInfo instanceof Array){
16287 Roo.each(this.selections, function(s) {
16288 this.unselect(s, nodeInfo);
16292 var node = this.getNode(nodeInfo);
16293 if(!node || !this.isSelected(node)){
16294 //Roo.log("not selected");
16295 return; // not selected.
16299 Roo.each(this.selections, function(s) {
16301 Roo.fly(node).removeClass(this.selectedClass);
16308 this.selections= ns;
16309 this.fireEvent("selectionchange", this, this.selections);
16313 * Gets a template node.
16314 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16315 * @return {HTMLElement} The node or null if it wasn't found
16317 getNode : function(nodeInfo){
16318 if(typeof nodeInfo == "string"){
16319 return document.getElementById(nodeInfo);
16320 }else if(typeof nodeInfo == "number"){
16321 return this.nodes[nodeInfo];
16327 * Gets a range template nodes.
16328 * @param {Number} startIndex
16329 * @param {Number} endIndex
16330 * @return {Array} An array of nodes
16332 getNodes : function(start, end){
16333 var ns = this.nodes;
16334 start = start || 0;
16335 end = typeof end == "undefined" ? ns.length - 1 : end;
16338 for(var i = start; i <= end; i++){
16342 for(var i = start; i >= end; i--){
16350 * Finds the index of the passed node
16351 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16352 * @return {Number} The index of the node or -1
16354 indexOf : function(node){
16355 node = this.getNode(node);
16356 if(typeof node.nodeIndex == "number"){
16357 return node.nodeIndex;
16359 var ns = this.nodes;
16360 for(var i = 0, len = ns.length; i < len; i++){
16371 * based on jquery fullcalendar
16375 Roo.bootstrap = Roo.bootstrap || {};
16377 * @class Roo.bootstrap.Calendar
16378 * @extends Roo.bootstrap.Component
16379 * Bootstrap Calendar class
16380 * @cfg {Boolean} loadMask (true|false) default false
16381 * @cfg {Object} header generate the user specific header of the calendar, default false
16384 * Create a new Container
16385 * @param {Object} config The config object
16390 Roo.bootstrap.Calendar = function(config){
16391 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16395 * Fires when a date is selected
16396 * @param {DatePicker} this
16397 * @param {Date} date The selected date
16401 * @event monthchange
16402 * Fires when the displayed month changes
16403 * @param {DatePicker} this
16404 * @param {Date} date The selected month
16406 'monthchange': true,
16408 * @event evententer
16409 * Fires when mouse over an event
16410 * @param {Calendar} this
16411 * @param {event} Event
16413 'evententer': true,
16415 * @event eventleave
16416 * Fires when the mouse leaves an
16417 * @param {Calendar} this
16420 'eventleave': true,
16422 * @event eventclick
16423 * Fires when the mouse click an
16424 * @param {Calendar} this
16433 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16436 * @cfg {Number} startDay
16437 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16445 getAutoCreate : function(){
16448 var fc_button = function(name, corner, style, content ) {
16449 return Roo.apply({},{
16451 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16453 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16456 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16467 style : 'width:100%',
16474 cls : 'fc-header-left',
16476 fc_button('prev', 'left', 'arrow', '‹' ),
16477 fc_button('next', 'right', 'arrow', '›' ),
16478 { tag: 'span', cls: 'fc-header-space' },
16479 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16487 cls : 'fc-header-center',
16491 cls: 'fc-header-title',
16494 html : 'month / year'
16502 cls : 'fc-header-right',
16504 /* fc_button('month', 'left', '', 'month' ),
16505 fc_button('week', '', '', 'week' ),
16506 fc_button('day', 'right', '', 'day' )
16518 header = this.header;
16521 var cal_heads = function() {
16523 // fixme - handle this.
16525 for (var i =0; i < Date.dayNames.length; i++) {
16526 var d = Date.dayNames[i];
16529 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16530 html : d.substring(0,3)
16534 ret[0].cls += ' fc-first';
16535 ret[6].cls += ' fc-last';
16538 var cal_cell = function(n) {
16541 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16546 cls: 'fc-day-number',
16550 cls: 'fc-day-content',
16554 style: 'position: relative;' // height: 17px;
16566 var cal_rows = function() {
16569 for (var r = 0; r < 6; r++) {
16576 for (var i =0; i < Date.dayNames.length; i++) {
16577 var d = Date.dayNames[i];
16578 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16581 row.cn[0].cls+=' fc-first';
16582 row.cn[0].cn[0].style = 'min-height:90px';
16583 row.cn[6].cls+=' fc-last';
16587 ret[0].cls += ' fc-first';
16588 ret[4].cls += ' fc-prev-last';
16589 ret[5].cls += ' fc-last';
16596 cls: 'fc-border-separate',
16597 style : 'width:100%',
16605 cls : 'fc-first fc-last',
16623 cls : 'fc-content',
16624 style : "position: relative;",
16627 cls : 'fc-view fc-view-month fc-grid',
16628 style : 'position: relative',
16629 unselectable : 'on',
16632 cls : 'fc-event-container',
16633 style : 'position:absolute;z-index:8;top:0;left:0;'
16651 initEvents : function()
16654 throw "can not find store for calendar";
16660 style: "text-align:center",
16664 style: "background-color:white;width:50%;margin:250 auto",
16668 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16679 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16681 var size = this.el.select('.fc-content', true).first().getSize();
16682 this.maskEl.setSize(size.width, size.height);
16683 this.maskEl.enableDisplayMode("block");
16684 if(!this.loadMask){
16685 this.maskEl.hide();
16688 this.store = Roo.factory(this.store, Roo.data);
16689 this.store.on('load', this.onLoad, this);
16690 this.store.on('beforeload', this.onBeforeLoad, this);
16694 this.cells = this.el.select('.fc-day',true);
16695 //Roo.log(this.cells);
16696 this.textNodes = this.el.query('.fc-day-number');
16697 this.cells.addClassOnOver('fc-state-hover');
16699 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16700 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16701 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16702 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16704 this.on('monthchange', this.onMonthChange, this);
16706 this.update(new Date().clearTime());
16709 resize : function() {
16710 var sz = this.el.getSize();
16712 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16713 this.el.select('.fc-day-content div',true).setHeight(34);
16718 showPrevMonth : function(e){
16719 this.update(this.activeDate.add("mo", -1));
16721 showToday : function(e){
16722 this.update(new Date().clearTime());
16725 showNextMonth : function(e){
16726 this.update(this.activeDate.add("mo", 1));
16730 showPrevYear : function(){
16731 this.update(this.activeDate.add("y", -1));
16735 showNextYear : function(){
16736 this.update(this.activeDate.add("y", 1));
16741 update : function(date)
16743 var vd = this.activeDate;
16744 this.activeDate = date;
16745 // if(vd && this.el){
16746 // var t = date.getTime();
16747 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16748 // Roo.log('using add remove');
16750 // this.fireEvent('monthchange', this, date);
16752 // this.cells.removeClass("fc-state-highlight");
16753 // this.cells.each(function(c){
16754 // if(c.dateValue == t){
16755 // c.addClass("fc-state-highlight");
16756 // setTimeout(function(){
16757 // try{c.dom.firstChild.focus();}catch(e){}
16767 var days = date.getDaysInMonth();
16769 var firstOfMonth = date.getFirstDateOfMonth();
16770 var startingPos = firstOfMonth.getDay()-this.startDay;
16772 if(startingPos < this.startDay){
16776 var pm = date.add(Date.MONTH, -1);
16777 var prevStart = pm.getDaysInMonth()-startingPos;
16779 this.cells = this.el.select('.fc-day',true);
16780 this.textNodes = this.el.query('.fc-day-number');
16781 this.cells.addClassOnOver('fc-state-hover');
16783 var cells = this.cells.elements;
16784 var textEls = this.textNodes;
16786 Roo.each(cells, function(cell){
16787 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16790 days += startingPos;
16792 // convert everything to numbers so it's fast
16793 var day = 86400000;
16794 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16797 //Roo.log(prevStart);
16799 var today = new Date().clearTime().getTime();
16800 var sel = date.clearTime().getTime();
16801 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16802 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16803 var ddMatch = this.disabledDatesRE;
16804 var ddText = this.disabledDatesText;
16805 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16806 var ddaysText = this.disabledDaysText;
16807 var format = this.format;
16809 var setCellClass = function(cal, cell){
16813 //Roo.log('set Cell Class');
16815 var t = d.getTime();
16819 cell.dateValue = t;
16821 cell.className += " fc-today";
16822 cell.className += " fc-state-highlight";
16823 cell.title = cal.todayText;
16826 // disable highlight in other month..
16827 //cell.className += " fc-state-highlight";
16832 cell.className = " fc-state-disabled";
16833 cell.title = cal.minText;
16837 cell.className = " fc-state-disabled";
16838 cell.title = cal.maxText;
16842 if(ddays.indexOf(d.getDay()) != -1){
16843 cell.title = ddaysText;
16844 cell.className = " fc-state-disabled";
16847 if(ddMatch && format){
16848 var fvalue = d.dateFormat(format);
16849 if(ddMatch.test(fvalue)){
16850 cell.title = ddText.replace("%0", fvalue);
16851 cell.className = " fc-state-disabled";
16855 if (!cell.initialClassName) {
16856 cell.initialClassName = cell.dom.className;
16859 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16864 for(; i < startingPos; i++) {
16865 textEls[i].innerHTML = (++prevStart);
16866 d.setDate(d.getDate()+1);
16868 cells[i].className = "fc-past fc-other-month";
16869 setCellClass(this, cells[i]);
16874 for(; i < days; i++){
16875 intDay = i - startingPos + 1;
16876 textEls[i].innerHTML = (intDay);
16877 d.setDate(d.getDate()+1);
16879 cells[i].className = ''; // "x-date-active";
16880 setCellClass(this, cells[i]);
16884 for(; i < 42; i++) {
16885 textEls[i].innerHTML = (++extraDays);
16886 d.setDate(d.getDate()+1);
16888 cells[i].className = "fc-future fc-other-month";
16889 setCellClass(this, cells[i]);
16892 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16894 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16896 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16897 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16899 if(totalRows != 6){
16900 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16901 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16904 this.fireEvent('monthchange', this, date);
16908 if(!this.internalRender){
16909 var main = this.el.dom.firstChild;
16910 var w = main.offsetWidth;
16911 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16912 Roo.fly(main).setWidth(w);
16913 this.internalRender = true;
16914 // opera does not respect the auto grow header center column
16915 // then, after it gets a width opera refuses to recalculate
16916 // without a second pass
16917 if(Roo.isOpera && !this.secondPass){
16918 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16919 this.secondPass = true;
16920 this.update.defer(10, this, [date]);
16927 findCell : function(dt) {
16928 dt = dt.clearTime().getTime();
16930 this.cells.each(function(c){
16931 //Roo.log("check " +c.dateValue + '?=' + dt);
16932 if(c.dateValue == dt){
16942 findCells : function(ev) {
16943 var s = ev.start.clone().clearTime().getTime();
16945 var e= ev.end.clone().clearTime().getTime();
16948 this.cells.each(function(c){
16949 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16951 if(c.dateValue > e){
16954 if(c.dateValue < s){
16963 // findBestRow: function(cells)
16967 // for (var i =0 ; i < cells.length;i++) {
16968 // ret = Math.max(cells[i].rows || 0,ret);
16975 addItem : function(ev)
16977 // look for vertical location slot in
16978 var cells = this.findCells(ev);
16980 // ev.row = this.findBestRow(cells);
16982 // work out the location.
16986 for(var i =0; i < cells.length; i++) {
16988 cells[i].row = cells[0].row;
16991 cells[i].row = cells[i].row + 1;
17001 if (crow.start.getY() == cells[i].getY()) {
17003 crow.end = cells[i];
17020 cells[0].events.push(ev);
17022 this.calevents.push(ev);
17025 clearEvents: function() {
17027 if(!this.calevents){
17031 Roo.each(this.cells.elements, function(c){
17037 Roo.each(this.calevents, function(e) {
17038 Roo.each(e.els, function(el) {
17039 el.un('mouseenter' ,this.onEventEnter, this);
17040 el.un('mouseleave' ,this.onEventLeave, this);
17045 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17051 renderEvents: function()
17055 this.cells.each(function(c) {
17064 if(c.row != c.events.length){
17065 r = 4 - (4 - (c.row - c.events.length));
17068 c.events = ev.slice(0, r);
17069 c.more = ev.slice(r);
17071 if(c.more.length && c.more.length == 1){
17072 c.events.push(c.more.pop());
17075 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17079 this.cells.each(function(c) {
17081 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17084 for (var e = 0; e < c.events.length; e++){
17085 var ev = c.events[e];
17086 var rows = ev.rows;
17088 for(var i = 0; i < rows.length; i++) {
17090 // how many rows should it span..
17093 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17094 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17096 unselectable : "on",
17099 cls: 'fc-event-inner',
17103 // cls: 'fc-event-time',
17104 // html : cells.length > 1 ? '' : ev.time
17108 cls: 'fc-event-title',
17109 html : String.format('{0}', ev.title)
17116 cls: 'ui-resizable-handle ui-resizable-e',
17117 html : '  '
17124 cfg.cls += ' fc-event-start';
17126 if ((i+1) == rows.length) {
17127 cfg.cls += ' fc-event-end';
17130 var ctr = _this.el.select('.fc-event-container',true).first();
17131 var cg = ctr.createChild(cfg);
17133 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17134 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17136 var r = (c.more.length) ? 1 : 0;
17137 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17138 cg.setWidth(ebox.right - sbox.x -2);
17140 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17141 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17142 cg.on('click', _this.onEventClick, _this, ev);
17153 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17154 style : 'position: absolute',
17155 unselectable : "on",
17158 cls: 'fc-event-inner',
17162 cls: 'fc-event-title',
17170 cls: 'ui-resizable-handle ui-resizable-e',
17171 html : '  '
17177 var ctr = _this.el.select('.fc-event-container',true).first();
17178 var cg = ctr.createChild(cfg);
17180 var sbox = c.select('.fc-day-content',true).first().getBox();
17181 var ebox = c.select('.fc-day-content',true).first().getBox();
17183 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17184 cg.setWidth(ebox.right - sbox.x -2);
17186 cg.on('click', _this.onMoreEventClick, _this, c.more);
17196 onEventEnter: function (e, el,event,d) {
17197 this.fireEvent('evententer', this, el, event);
17200 onEventLeave: function (e, el,event,d) {
17201 this.fireEvent('eventleave', this, el, event);
17204 onEventClick: function (e, el,event,d) {
17205 this.fireEvent('eventclick', this, el, event);
17208 onMonthChange: function () {
17212 onMoreEventClick: function(e, el, more)
17216 this.calpopover.placement = 'right';
17217 this.calpopover.setTitle('More');
17219 this.calpopover.setContent('');
17221 var ctr = this.calpopover.el.select('.popover-content', true).first();
17223 Roo.each(more, function(m){
17225 cls : 'fc-event-hori fc-event-draggable',
17228 var cg = ctr.createChild(cfg);
17230 cg.on('click', _this.onEventClick, _this, m);
17233 this.calpopover.show(el);
17238 onLoad: function ()
17240 this.calevents = [];
17243 if(this.store.getCount() > 0){
17244 this.store.data.each(function(d){
17247 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17248 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17249 time : d.data.start_time,
17250 title : d.data.title,
17251 description : d.data.description,
17252 venue : d.data.venue
17257 this.renderEvents();
17259 if(this.calevents.length && this.loadMask){
17260 this.maskEl.hide();
17264 onBeforeLoad: function()
17266 this.clearEvents();
17268 this.maskEl.show();
17282 * @class Roo.bootstrap.Popover
17283 * @extends Roo.bootstrap.Component
17284 * Bootstrap Popover class
17285 * @cfg {String} html contents of the popover (or false to use children..)
17286 * @cfg {String} title of popover (or false to hide)
17287 * @cfg {String} placement how it is placed
17288 * @cfg {String} trigger click || hover (or false to trigger manually)
17289 * @cfg {String} over what (parent or false to trigger manually.)
17290 * @cfg {Number} delay - delay before showing
17293 * Create a new Popover
17294 * @param {Object} config The config object
17297 Roo.bootstrap.Popover = function(config){
17298 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17304 * After the popover show
17306 * @param {Roo.bootstrap.Popover} this
17311 * After the popover hide
17313 * @param {Roo.bootstrap.Popover} this
17319 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17321 title: 'Fill in a title',
17324 placement : 'right',
17325 trigger : 'hover', // hover
17331 can_build_overlaid : false,
17333 getChildContainer : function()
17335 return this.el.select('.popover-content',true).first();
17338 getAutoCreate : function(){
17341 cls : 'popover roo-dynamic',
17342 style: 'display:block',
17348 cls : 'popover-inner',
17352 cls: 'popover-title',
17356 cls : 'popover-content',
17367 setTitle: function(str)
17370 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17372 setContent: function(str)
17375 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17377 // as it get's added to the bottom of the page.
17378 onRender : function(ct, position)
17380 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17382 var cfg = Roo.apply({}, this.getAutoCreate());
17386 cfg.cls += ' ' + this.cls;
17389 cfg.style = this.style;
17391 //Roo.log("adding to ");
17392 this.el = Roo.get(document.body).createChild(cfg, position);
17393 // Roo.log(this.el);
17398 initEvents : function()
17400 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17401 this.el.enableDisplayMode('block');
17403 if (this.over === false) {
17406 if (this.triggers === false) {
17409 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17410 var triggers = this.trigger ? this.trigger.split(' ') : [];
17411 Roo.each(triggers, function(trigger) {
17413 if (trigger == 'click') {
17414 on_el.on('click', this.toggle, this);
17415 } else if (trigger != 'manual') {
17416 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17417 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17419 on_el.on(eventIn ,this.enter, this);
17420 on_el.on(eventOut, this.leave, this);
17431 toggle : function () {
17432 this.hoverState == 'in' ? this.leave() : this.enter();
17435 enter : function () {
17437 clearTimeout(this.timeout);
17439 this.hoverState = 'in';
17441 if (!this.delay || !this.delay.show) {
17446 this.timeout = setTimeout(function () {
17447 if (_t.hoverState == 'in') {
17450 }, this.delay.show)
17453 leave : function() {
17454 clearTimeout(this.timeout);
17456 this.hoverState = 'out';
17458 if (!this.delay || !this.delay.hide) {
17463 this.timeout = setTimeout(function () {
17464 if (_t.hoverState == 'out') {
17467 }, this.delay.hide)
17470 show : function (on_el)
17473 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17477 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17478 if (this.html !== false) {
17479 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17481 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17482 if (!this.title.length) {
17483 this.el.select('.popover-title',true).hide();
17486 var placement = typeof this.placement == 'function' ?
17487 this.placement.call(this, this.el, on_el) :
17490 var autoToken = /\s?auto?\s?/i;
17491 var autoPlace = autoToken.test(placement);
17493 placement = placement.replace(autoToken, '') || 'top';
17497 //this.el.setXY([0,0]);
17499 this.el.dom.style.display='block';
17500 this.el.addClass(placement);
17502 //this.el.appendTo(on_el);
17504 var p = this.getPosition();
17505 var box = this.el.getBox();
17510 var align = Roo.bootstrap.Popover.alignment[placement];
17513 this.el.alignTo(on_el, align[0],align[1]);
17514 //var arrow = this.el.select('.arrow',true).first();
17515 //arrow.set(align[2],
17517 this.el.addClass('in');
17520 if (this.el.hasClass('fade')) {
17524 this.hoverState = 'in';
17526 this.fireEvent('show', this);
17531 this.el.setXY([0,0]);
17532 this.el.removeClass('in');
17534 this.hoverState = null;
17536 this.fireEvent('hide', this);
17541 Roo.bootstrap.Popover.alignment = {
17542 'left' : ['r-l', [-10,0], 'right'],
17543 'right' : ['l-r', [10,0], 'left'],
17544 'bottom' : ['t-b', [0,10], 'top'],
17545 'top' : [ 'b-t', [0,-10], 'bottom']
17556 * @class Roo.bootstrap.Progress
17557 * @extends Roo.bootstrap.Component
17558 * Bootstrap Progress class
17559 * @cfg {Boolean} striped striped of the progress bar
17560 * @cfg {Boolean} active animated of the progress bar
17564 * Create a new Progress
17565 * @param {Object} config The config object
17568 Roo.bootstrap.Progress = function(config){
17569 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17572 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17577 getAutoCreate : function(){
17585 cfg.cls += ' progress-striped';
17589 cfg.cls += ' active';
17608 * @class Roo.bootstrap.ProgressBar
17609 * @extends Roo.bootstrap.Component
17610 * Bootstrap ProgressBar class
17611 * @cfg {Number} aria_valuenow aria-value now
17612 * @cfg {Number} aria_valuemin aria-value min
17613 * @cfg {Number} aria_valuemax aria-value max
17614 * @cfg {String} label label for the progress bar
17615 * @cfg {String} panel (success | info | warning | danger )
17616 * @cfg {String} role role of the progress bar
17617 * @cfg {String} sr_only text
17621 * Create a new ProgressBar
17622 * @param {Object} config The config object
17625 Roo.bootstrap.ProgressBar = function(config){
17626 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17629 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17633 aria_valuemax : 100,
17639 getAutoCreate : function()
17644 cls: 'progress-bar',
17645 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17657 cfg.role = this.role;
17660 if(this.aria_valuenow){
17661 cfg['aria-valuenow'] = this.aria_valuenow;
17664 if(this.aria_valuemin){
17665 cfg['aria-valuemin'] = this.aria_valuemin;
17668 if(this.aria_valuemax){
17669 cfg['aria-valuemax'] = this.aria_valuemax;
17672 if(this.label && !this.sr_only){
17673 cfg.html = this.label;
17677 cfg.cls += ' progress-bar-' + this.panel;
17683 update : function(aria_valuenow)
17685 this.aria_valuenow = aria_valuenow;
17687 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17702 * @class Roo.bootstrap.TabGroup
17703 * @extends Roo.bootstrap.Column
17704 * Bootstrap Column class
17705 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17706 * @cfg {Boolean} carousel true to make the group behave like a carousel
17707 * @cfg {Boolean} bullets show bullets for the panels
17708 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17709 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17710 * @cfg {Boolean} showarrow (true|false) show arrow default true
17713 * Create a new TabGroup
17714 * @param {Object} config The config object
17717 Roo.bootstrap.TabGroup = function(config){
17718 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17720 this.navId = Roo.id();
17723 Roo.bootstrap.TabGroup.register(this);
17727 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17730 transition : false,
17735 slideOnTouch : false,
17738 getAutoCreate : function()
17740 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17742 cfg.cls += ' tab-content';
17744 if (this.carousel) {
17745 cfg.cls += ' carousel slide';
17748 cls : 'carousel-inner',
17752 if(this.bullets && !Roo.isTouch){
17755 cls : 'carousel-bullets',
17759 if(this.bullets_cls){
17760 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17767 cfg.cn[0].cn.push(bullets);
17770 if(this.showarrow){
17771 cfg.cn[0].cn.push({
17773 class : 'carousel-arrow',
17777 class : 'carousel-prev',
17781 class : 'fa fa-chevron-left'
17787 class : 'carousel-next',
17791 class : 'fa fa-chevron-right'
17804 initEvents: function()
17806 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17807 // this.el.on("touchstart", this.onTouchStart, this);
17810 if(this.autoslide){
17813 this.slideFn = window.setInterval(function() {
17814 _this.showPanelNext();
17818 if(this.showarrow){
17819 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17820 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17826 // onTouchStart : function(e, el, o)
17828 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17832 // this.showPanelNext();
17836 getChildContainer : function()
17838 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17842 * register a Navigation item
17843 * @param {Roo.bootstrap.NavItem} the navitem to add
17845 register : function(item)
17847 this.tabs.push( item);
17848 item.navId = this.navId; // not really needed..
17853 getActivePanel : function()
17856 Roo.each(this.tabs, function(t) {
17866 getPanelByName : function(n)
17869 Roo.each(this.tabs, function(t) {
17870 if (t.tabId == n) {
17878 indexOfPanel : function(p)
17881 Roo.each(this.tabs, function(t,i) {
17882 if (t.tabId == p.tabId) {
17891 * show a specific panel
17892 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17893 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17895 showPanel : function (pan)
17897 if(this.transition || typeof(pan) == 'undefined'){
17898 Roo.log("waiting for the transitionend");
17902 if (typeof(pan) == 'number') {
17903 pan = this.tabs[pan];
17906 if (typeof(pan) == 'string') {
17907 pan = this.getPanelByName(pan);
17910 var cur = this.getActivePanel();
17913 Roo.log('pan or acitve pan is undefined');
17917 if (pan.tabId == this.getActivePanel().tabId) {
17921 if (false === cur.fireEvent('beforedeactivate')) {
17925 if(this.bullets > 0 && !Roo.isTouch){
17926 this.setActiveBullet(this.indexOfPanel(pan));
17929 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17931 this.transition = true;
17932 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17933 var lr = dir == 'next' ? 'left' : 'right';
17934 pan.el.addClass(dir); // or prev
17935 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17936 cur.el.addClass(lr); // or right
17937 pan.el.addClass(lr);
17940 cur.el.on('transitionend', function() {
17941 Roo.log("trans end?");
17943 pan.el.removeClass([lr,dir]);
17944 pan.setActive(true);
17946 cur.el.removeClass([lr]);
17947 cur.setActive(false);
17949 _this.transition = false;
17951 }, this, { single: true } );
17956 cur.setActive(false);
17957 pan.setActive(true);
17962 showPanelNext : function()
17964 var i = this.indexOfPanel(this.getActivePanel());
17966 if (i >= this.tabs.length - 1 && !this.autoslide) {
17970 if (i >= this.tabs.length - 1 && this.autoslide) {
17974 this.showPanel(this.tabs[i+1]);
17977 showPanelPrev : function()
17979 var i = this.indexOfPanel(this.getActivePanel());
17981 if (i < 1 && !this.autoslide) {
17985 if (i < 1 && this.autoslide) {
17986 i = this.tabs.length;
17989 this.showPanel(this.tabs[i-1]);
17993 addBullet: function()
17995 if(!this.bullets || Roo.isTouch){
17998 var ctr = this.el.select('.carousel-bullets',true).first();
17999 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18000 var bullet = ctr.createChild({
18001 cls : 'bullet bullet-' + i
18002 },ctr.dom.lastChild);
18007 bullet.on('click', (function(e, el, o, ii, t){
18009 e.preventDefault();
18011 this.showPanel(ii);
18013 if(this.autoslide && this.slideFn){
18014 clearInterval(this.slideFn);
18015 this.slideFn = window.setInterval(function() {
18016 _this.showPanelNext();
18020 }).createDelegate(this, [i, bullet], true));
18025 setActiveBullet : function(i)
18031 Roo.each(this.el.select('.bullet', true).elements, function(el){
18032 el.removeClass('selected');
18035 var bullet = this.el.select('.bullet-' + i, true).first();
18041 bullet.addClass('selected');
18052 Roo.apply(Roo.bootstrap.TabGroup, {
18056 * register a Navigation Group
18057 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18059 register : function(navgrp)
18061 this.groups[navgrp.navId] = navgrp;
18065 * fetch a Navigation Group based on the navigation ID
18066 * if one does not exist , it will get created.
18067 * @param {string} the navgroup to add
18068 * @returns {Roo.bootstrap.NavGroup} the navgroup
18070 get: function(navId) {
18071 if (typeof(this.groups[navId]) == 'undefined') {
18072 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18074 return this.groups[navId] ;
18089 * @class Roo.bootstrap.TabPanel
18090 * @extends Roo.bootstrap.Component
18091 * Bootstrap TabPanel class
18092 * @cfg {Boolean} active panel active
18093 * @cfg {String} html panel content
18094 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18095 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18096 * @cfg {String} href click to link..
18100 * Create a new TabPanel
18101 * @param {Object} config The config object
18104 Roo.bootstrap.TabPanel = function(config){
18105 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18109 * Fires when the active status changes
18110 * @param {Roo.bootstrap.TabPanel} this
18111 * @param {Boolean} state the new state
18116 * @event beforedeactivate
18117 * Fires before a tab is de-activated - can be used to do validation on a form.
18118 * @param {Roo.bootstrap.TabPanel} this
18119 * @return {Boolean} false if there is an error
18122 'beforedeactivate': true
18125 this.tabId = this.tabId || Roo.id();
18129 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18137 getAutoCreate : function(){
18140 // item is needed for carousel - not sure if it has any effect otherwise
18141 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18142 html: this.html || ''
18146 cfg.cls += ' active';
18150 cfg.tabId = this.tabId;
18157 initEvents: function()
18159 var p = this.parent();
18161 this.navId = this.navId || p.navId;
18163 if (typeof(this.navId) != 'undefined') {
18164 // not really needed.. but just in case.. parent should be a NavGroup.
18165 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18169 var i = tg.tabs.length - 1;
18171 if(this.active && tg.bullets > 0 && i < tg.bullets){
18172 tg.setActiveBullet(i);
18176 this.el.on('click', this.onClick, this);
18179 this.el.on("touchstart", this.onTouchStart, this);
18180 this.el.on("touchmove", this.onTouchMove, this);
18181 this.el.on("touchend", this.onTouchEnd, this);
18186 onRender : function(ct, position)
18188 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18191 setActive : function(state)
18193 Roo.log("panel - set active " + this.tabId + "=" + state);
18195 this.active = state;
18197 this.el.removeClass('active');
18199 } else if (!this.el.hasClass('active')) {
18200 this.el.addClass('active');
18203 this.fireEvent('changed', this, state);
18206 onClick : function(e)
18208 e.preventDefault();
18210 if(!this.href.length){
18214 window.location.href = this.href;
18223 onTouchStart : function(e)
18225 this.swiping = false;
18227 this.startX = e.browserEvent.touches[0].clientX;
18228 this.startY = e.browserEvent.touches[0].clientY;
18231 onTouchMove : function(e)
18233 this.swiping = true;
18235 this.endX = e.browserEvent.touches[0].clientX;
18236 this.endY = e.browserEvent.touches[0].clientY;
18239 onTouchEnd : function(e)
18246 var tabGroup = this.parent();
18248 if(this.endX > this.startX){ // swiping right
18249 tabGroup.showPanelPrev();
18253 if(this.startX > this.endX){ // swiping left
18254 tabGroup.showPanelNext();
18273 * @class Roo.bootstrap.DateField
18274 * @extends Roo.bootstrap.Input
18275 * Bootstrap DateField class
18276 * @cfg {Number} weekStart default 0
18277 * @cfg {String} viewMode default empty, (months|years)
18278 * @cfg {String} minViewMode default empty, (months|years)
18279 * @cfg {Number} startDate default -Infinity
18280 * @cfg {Number} endDate default Infinity
18281 * @cfg {Boolean} todayHighlight default false
18282 * @cfg {Boolean} todayBtn default false
18283 * @cfg {Boolean} calendarWeeks default false
18284 * @cfg {Object} daysOfWeekDisabled default empty
18285 * @cfg {Boolean} singleMode default false (true | false)
18287 * @cfg {Boolean} keyboardNavigation default true
18288 * @cfg {String} language default en
18291 * Create a new DateField
18292 * @param {Object} config The config object
18295 Roo.bootstrap.DateField = function(config){
18296 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18300 * Fires when this field show.
18301 * @param {Roo.bootstrap.DateField} this
18302 * @param {Mixed} date The date value
18307 * Fires when this field hide.
18308 * @param {Roo.bootstrap.DateField} this
18309 * @param {Mixed} date The date value
18314 * Fires when select a date.
18315 * @param {Roo.bootstrap.DateField} this
18316 * @param {Mixed} date The date value
18320 * @event beforeselect
18321 * Fires when before select a date.
18322 * @param {Roo.bootstrap.DateField} this
18323 * @param {Mixed} date The date value
18325 beforeselect : true
18329 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18332 * @cfg {String} format
18333 * The default date format string which can be overriden for localization support. The format must be
18334 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18338 * @cfg {String} altFormats
18339 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18340 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18342 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18350 todayHighlight : false,
18356 keyboardNavigation: true,
18358 calendarWeeks: false,
18360 startDate: -Infinity,
18364 daysOfWeekDisabled: [],
18368 singleMode : false,
18370 UTCDate: function()
18372 return new Date(Date.UTC.apply(Date, arguments));
18375 UTCToday: function()
18377 var today = new Date();
18378 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18381 getDate: function() {
18382 var d = this.getUTCDate();
18383 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18386 getUTCDate: function() {
18390 setDate: function(d) {
18391 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18394 setUTCDate: function(d) {
18396 this.setValue(this.formatDate(this.date));
18399 onRender: function(ct, position)
18402 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18404 this.language = this.language || 'en';
18405 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18406 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18408 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18409 this.format = this.format || 'm/d/y';
18410 this.isInline = false;
18411 this.isInput = true;
18412 this.component = this.el.select('.add-on', true).first() || false;
18413 this.component = (this.component && this.component.length === 0) ? false : this.component;
18414 this.hasInput = this.component && this.inputEl().length;
18416 if (typeof(this.minViewMode === 'string')) {
18417 switch (this.minViewMode) {
18419 this.minViewMode = 1;
18422 this.minViewMode = 2;
18425 this.minViewMode = 0;
18430 if (typeof(this.viewMode === 'string')) {
18431 switch (this.viewMode) {
18444 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18446 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18448 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18450 this.picker().on('mousedown', this.onMousedown, this);
18451 this.picker().on('click', this.onClick, this);
18453 this.picker().addClass('datepicker-dropdown');
18455 this.startViewMode = this.viewMode;
18457 if(this.singleMode){
18458 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18459 v.setVisibilityMode(Roo.Element.DISPLAY);
18463 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18464 v.setStyle('width', '189px');
18468 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18469 if(!this.calendarWeeks){
18474 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18475 v.attr('colspan', function(i, val){
18476 return parseInt(val) + 1;
18481 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18483 this.setStartDate(this.startDate);
18484 this.setEndDate(this.endDate);
18486 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18493 if(this.isInline) {
18498 picker : function()
18500 return this.pickerEl;
18501 // return this.el.select('.datepicker', true).first();
18504 fillDow: function()
18506 var dowCnt = this.weekStart;
18515 if(this.calendarWeeks){
18523 while (dowCnt < this.weekStart + 7) {
18527 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18531 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18534 fillMonths: function()
18537 var months = this.picker().select('>.datepicker-months td', true).first();
18539 months.dom.innerHTML = '';
18545 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18548 months.createChild(month);
18555 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;
18557 if (this.date < this.startDate) {
18558 this.viewDate = new Date(this.startDate);
18559 } else if (this.date > this.endDate) {
18560 this.viewDate = new Date(this.endDate);
18562 this.viewDate = new Date(this.date);
18570 var d = new Date(this.viewDate),
18571 year = d.getUTCFullYear(),
18572 month = d.getUTCMonth(),
18573 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18574 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18575 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18576 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18577 currentDate = this.date && this.date.valueOf(),
18578 today = this.UTCToday();
18580 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18582 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18584 // this.picker.select('>tfoot th.today').
18585 // .text(dates[this.language].today)
18586 // .toggle(this.todayBtn !== false);
18588 this.updateNavArrows();
18591 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18593 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18595 prevMonth.setUTCDate(day);
18597 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18599 var nextMonth = new Date(prevMonth);
18601 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18603 nextMonth = nextMonth.valueOf();
18605 var fillMonths = false;
18607 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18609 while(prevMonth.valueOf() < nextMonth) {
18612 if (prevMonth.getUTCDay() === this.weekStart) {
18614 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18622 if(this.calendarWeeks){
18623 // ISO 8601: First week contains first thursday.
18624 // ISO also states week starts on Monday, but we can be more abstract here.
18626 // Start of current week: based on weekstart/current date
18627 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18628 // Thursday of this week
18629 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18630 // First Thursday of year, year from thursday
18631 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18632 // Calendar week: ms between thursdays, div ms per day, div 7 days
18633 calWeek = (th - yth) / 864e5 / 7 + 1;
18635 fillMonths.cn.push({
18643 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18645 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18648 if (this.todayHighlight &&
18649 prevMonth.getUTCFullYear() == today.getFullYear() &&
18650 prevMonth.getUTCMonth() == today.getMonth() &&
18651 prevMonth.getUTCDate() == today.getDate()) {
18652 clsName += ' today';
18655 if (currentDate && prevMonth.valueOf() === currentDate) {
18656 clsName += ' active';
18659 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18660 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18661 clsName += ' disabled';
18664 fillMonths.cn.push({
18666 cls: 'day ' + clsName,
18667 html: prevMonth.getDate()
18670 prevMonth.setDate(prevMonth.getDate()+1);
18673 var currentYear = this.date && this.date.getUTCFullYear();
18674 var currentMonth = this.date && this.date.getUTCMonth();
18676 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18678 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18679 v.removeClass('active');
18681 if(currentYear === year && k === currentMonth){
18682 v.addClass('active');
18685 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18686 v.addClass('disabled');
18692 year = parseInt(year/10, 10) * 10;
18694 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18696 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18699 for (var i = -1; i < 11; i++) {
18700 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18702 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18710 showMode: function(dir)
18713 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18716 Roo.each(this.picker().select('>div',true).elements, function(v){
18717 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18720 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18725 if(this.isInline) {
18729 this.picker().removeClass(['bottom', 'top']);
18731 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18733 * place to the top of element!
18737 this.picker().addClass('top');
18738 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18743 this.picker().addClass('bottom');
18745 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18748 parseDate : function(value)
18750 if(!value || value instanceof Date){
18753 var v = Date.parseDate(value, this.format);
18754 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18755 v = Date.parseDate(value, 'Y-m-d');
18757 if(!v && this.altFormats){
18758 if(!this.altFormatsArray){
18759 this.altFormatsArray = this.altFormats.split("|");
18761 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18762 v = Date.parseDate(value, this.altFormatsArray[i]);
18768 formatDate : function(date, fmt)
18770 return (!date || !(date instanceof Date)) ?
18771 date : date.dateFormat(fmt || this.format);
18774 onFocus : function()
18776 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18780 onBlur : function()
18782 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18784 var d = this.inputEl().getValue();
18793 this.picker().show();
18797 this.fireEvent('show', this, this.date);
18802 if(this.isInline) {
18805 this.picker().hide();
18806 this.viewMode = this.startViewMode;
18809 this.fireEvent('hide', this, this.date);
18813 onMousedown: function(e)
18815 e.stopPropagation();
18816 e.preventDefault();
18821 Roo.bootstrap.DateField.superclass.keyup.call(this);
18825 setValue: function(v)
18827 if(this.fireEvent('beforeselect', this, v) !== false){
18828 var d = new Date(this.parseDate(v) ).clearTime();
18830 if(isNaN(d.getTime())){
18831 this.date = this.viewDate = '';
18832 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18836 v = this.formatDate(d);
18838 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18840 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18844 this.fireEvent('select', this, this.date);
18848 getValue: function()
18850 return this.formatDate(this.date);
18853 fireKey: function(e)
18855 if (!this.picker().isVisible()){
18856 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18862 var dateChanged = false,
18864 newDate, newViewDate;
18869 e.preventDefault();
18873 if (!this.keyboardNavigation) {
18876 dir = e.keyCode == 37 ? -1 : 1;
18879 newDate = this.moveYear(this.date, dir);
18880 newViewDate = this.moveYear(this.viewDate, dir);
18881 } else if (e.shiftKey){
18882 newDate = this.moveMonth(this.date, dir);
18883 newViewDate = this.moveMonth(this.viewDate, dir);
18885 newDate = new Date(this.date);
18886 newDate.setUTCDate(this.date.getUTCDate() + dir);
18887 newViewDate = new Date(this.viewDate);
18888 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18890 if (this.dateWithinRange(newDate)){
18891 this.date = newDate;
18892 this.viewDate = newViewDate;
18893 this.setValue(this.formatDate(this.date));
18895 e.preventDefault();
18896 dateChanged = true;
18901 if (!this.keyboardNavigation) {
18904 dir = e.keyCode == 38 ? -1 : 1;
18906 newDate = this.moveYear(this.date, dir);
18907 newViewDate = this.moveYear(this.viewDate, dir);
18908 } else if (e.shiftKey){
18909 newDate = this.moveMonth(this.date, dir);
18910 newViewDate = this.moveMonth(this.viewDate, dir);
18912 newDate = new Date(this.date);
18913 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18914 newViewDate = new Date(this.viewDate);
18915 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18917 if (this.dateWithinRange(newDate)){
18918 this.date = newDate;
18919 this.viewDate = newViewDate;
18920 this.setValue(this.formatDate(this.date));
18922 e.preventDefault();
18923 dateChanged = true;
18927 this.setValue(this.formatDate(this.date));
18929 e.preventDefault();
18932 this.setValue(this.formatDate(this.date));
18946 onClick: function(e)
18948 e.stopPropagation();
18949 e.preventDefault();
18951 var target = e.getTarget();
18953 if(target.nodeName.toLowerCase() === 'i'){
18954 target = Roo.get(target).dom.parentNode;
18957 var nodeName = target.nodeName;
18958 var className = target.className;
18959 var html = target.innerHTML;
18960 //Roo.log(nodeName);
18962 switch(nodeName.toLowerCase()) {
18964 switch(className) {
18970 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18971 switch(this.viewMode){
18973 this.viewDate = this.moveMonth(this.viewDate, dir);
18977 this.viewDate = this.moveYear(this.viewDate, dir);
18983 var date = new Date();
18984 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18986 this.setValue(this.formatDate(this.date));
18993 if (className.indexOf('disabled') < 0) {
18994 this.viewDate.setUTCDate(1);
18995 if (className.indexOf('month') > -1) {
18996 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
18998 var year = parseInt(html, 10) || 0;
18999 this.viewDate.setUTCFullYear(year);
19003 if(this.singleMode){
19004 this.setValue(this.formatDate(this.viewDate));
19015 //Roo.log(className);
19016 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19017 var day = parseInt(html, 10) || 1;
19018 var year = this.viewDate.getUTCFullYear(),
19019 month = this.viewDate.getUTCMonth();
19021 if (className.indexOf('old') > -1) {
19028 } else if (className.indexOf('new') > -1) {
19036 //Roo.log([year,month,day]);
19037 this.date = this.UTCDate(year, month, day,0,0,0,0);
19038 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19040 //Roo.log(this.formatDate(this.date));
19041 this.setValue(this.formatDate(this.date));
19048 setStartDate: function(startDate)
19050 this.startDate = startDate || -Infinity;
19051 if (this.startDate !== -Infinity) {
19052 this.startDate = this.parseDate(this.startDate);
19055 this.updateNavArrows();
19058 setEndDate: function(endDate)
19060 this.endDate = endDate || Infinity;
19061 if (this.endDate !== Infinity) {
19062 this.endDate = this.parseDate(this.endDate);
19065 this.updateNavArrows();
19068 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19070 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19071 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19072 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19074 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19075 return parseInt(d, 10);
19078 this.updateNavArrows();
19081 updateNavArrows: function()
19083 if(this.singleMode){
19087 var d = new Date(this.viewDate),
19088 year = d.getUTCFullYear(),
19089 month = d.getUTCMonth();
19091 Roo.each(this.picker().select('.prev', true).elements, function(v){
19093 switch (this.viewMode) {
19096 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19102 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19109 Roo.each(this.picker().select('.next', true).elements, function(v){
19111 switch (this.viewMode) {
19114 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19120 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19128 moveMonth: function(date, dir)
19133 var new_date = new Date(date.valueOf()),
19134 day = new_date.getUTCDate(),
19135 month = new_date.getUTCMonth(),
19136 mag = Math.abs(dir),
19138 dir = dir > 0 ? 1 : -1;
19141 // If going back one month, make sure month is not current month
19142 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19144 return new_date.getUTCMonth() == month;
19146 // If going forward one month, make sure month is as expected
19147 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19149 return new_date.getUTCMonth() != new_month;
19151 new_month = month + dir;
19152 new_date.setUTCMonth(new_month);
19153 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19154 if (new_month < 0 || new_month > 11) {
19155 new_month = (new_month + 12) % 12;
19158 // For magnitudes >1, move one month at a time...
19159 for (var i=0; i<mag; i++) {
19160 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19161 new_date = this.moveMonth(new_date, dir);
19163 // ...then reset the day, keeping it in the new month
19164 new_month = new_date.getUTCMonth();
19165 new_date.setUTCDate(day);
19167 return new_month != new_date.getUTCMonth();
19170 // Common date-resetting loop -- if date is beyond end of month, make it
19173 new_date.setUTCDate(--day);
19174 new_date.setUTCMonth(new_month);
19179 moveYear: function(date, dir)
19181 return this.moveMonth(date, dir*12);
19184 dateWithinRange: function(date)
19186 return date >= this.startDate && date <= this.endDate;
19192 this.picker().remove();
19195 validateValue : function(value)
19197 if(this.getVisibilityEl().hasClass('hidden')){
19201 if(value.length < 1) {
19202 if(this.allowBlank){
19208 if(value.length < this.minLength){
19211 if(value.length > this.maxLength){
19215 var vt = Roo.form.VTypes;
19216 if(!vt[this.vtype](value, this)){
19220 if(typeof this.validator == "function"){
19221 var msg = this.validator(value);
19227 if(this.regex && !this.regex.test(value)){
19231 if(typeof(this.parseDate(value)) == 'undefined'){
19235 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19239 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19247 setVisible : function(visible)
19253 this.getEl().removeClass('hidden');
19259 this.getEl().addClass('hidden');
19264 Roo.apply(Roo.bootstrap.DateField, {
19275 html: '<i class="fa fa-arrow-left"/>'
19285 html: '<i class="fa fa-arrow-right"/>'
19327 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19328 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19329 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19330 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19331 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19344 navFnc: 'FullYear',
19349 navFnc: 'FullYear',
19354 Roo.apply(Roo.bootstrap.DateField, {
19358 cls: 'datepicker dropdown-menu roo-dynamic',
19362 cls: 'datepicker-days',
19366 cls: 'table-condensed',
19368 Roo.bootstrap.DateField.head,
19372 Roo.bootstrap.DateField.footer
19379 cls: 'datepicker-months',
19383 cls: 'table-condensed',
19385 Roo.bootstrap.DateField.head,
19386 Roo.bootstrap.DateField.content,
19387 Roo.bootstrap.DateField.footer
19394 cls: 'datepicker-years',
19398 cls: 'table-condensed',
19400 Roo.bootstrap.DateField.head,
19401 Roo.bootstrap.DateField.content,
19402 Roo.bootstrap.DateField.footer
19421 * @class Roo.bootstrap.TimeField
19422 * @extends Roo.bootstrap.Input
19423 * Bootstrap DateField class
19427 * Create a new TimeField
19428 * @param {Object} config The config object
19431 Roo.bootstrap.TimeField = function(config){
19432 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19436 * Fires when this field show.
19437 * @param {Roo.bootstrap.DateField} thisthis
19438 * @param {Mixed} date The date value
19443 * Fires when this field hide.
19444 * @param {Roo.bootstrap.DateField} this
19445 * @param {Mixed} date The date value
19450 * Fires when select a date.
19451 * @param {Roo.bootstrap.DateField} this
19452 * @param {Mixed} date The date value
19458 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19461 * @cfg {String} format
19462 * The default time format string which can be overriden for localization support. The format must be
19463 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19467 onRender: function(ct, position)
19470 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19472 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19474 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19476 this.pop = this.picker().select('>.datepicker-time',true).first();
19477 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19479 this.picker().on('mousedown', this.onMousedown, this);
19480 this.picker().on('click', this.onClick, this);
19482 this.picker().addClass('datepicker-dropdown');
19487 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19488 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19489 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19490 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19491 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19492 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19496 fireKey: function(e){
19497 if (!this.picker().isVisible()){
19498 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19504 e.preventDefault();
19512 this.onTogglePeriod();
19515 this.onIncrementMinutes();
19518 this.onDecrementMinutes();
19527 onClick: function(e) {
19528 e.stopPropagation();
19529 e.preventDefault();
19532 picker : function()
19534 return this.el.select('.datepicker', true).first();
19537 fillTime: function()
19539 var time = this.pop.select('tbody', true).first();
19541 time.dom.innerHTML = '';
19556 cls: 'hours-up glyphicon glyphicon-chevron-up'
19576 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19597 cls: 'timepicker-hour',
19612 cls: 'timepicker-minute',
19627 cls: 'btn btn-primary period',
19649 cls: 'hours-down glyphicon glyphicon-chevron-down'
19669 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19687 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19694 var hours = this.time.getHours();
19695 var minutes = this.time.getMinutes();
19708 hours = hours - 12;
19712 hours = '0' + hours;
19716 minutes = '0' + minutes;
19719 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19720 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19721 this.pop.select('button', true).first().dom.innerHTML = period;
19727 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19729 var cls = ['bottom'];
19731 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19738 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19743 this.picker().addClass(cls.join('-'));
19747 Roo.each(cls, function(c){
19749 _this.picker().setTop(_this.inputEl().getHeight());
19753 _this.picker().setTop(0 - _this.picker().getHeight());
19758 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19762 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19769 onFocus : function()
19771 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19775 onBlur : function()
19777 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19783 this.picker().show();
19788 this.fireEvent('show', this, this.date);
19793 this.picker().hide();
19796 this.fireEvent('hide', this, this.date);
19799 setTime : function()
19802 this.setValue(this.time.format(this.format));
19804 this.fireEvent('select', this, this.date);
19809 onMousedown: function(e){
19810 e.stopPropagation();
19811 e.preventDefault();
19814 onIncrementHours: function()
19816 Roo.log('onIncrementHours');
19817 this.time = this.time.add(Date.HOUR, 1);
19822 onDecrementHours: function()
19824 Roo.log('onDecrementHours');
19825 this.time = this.time.add(Date.HOUR, -1);
19829 onIncrementMinutes: function()
19831 Roo.log('onIncrementMinutes');
19832 this.time = this.time.add(Date.MINUTE, 1);
19836 onDecrementMinutes: function()
19838 Roo.log('onDecrementMinutes');
19839 this.time = this.time.add(Date.MINUTE, -1);
19843 onTogglePeriod: function()
19845 Roo.log('onTogglePeriod');
19846 this.time = this.time.add(Date.HOUR, 12);
19853 Roo.apply(Roo.bootstrap.TimeField, {
19883 cls: 'btn btn-info ok',
19895 Roo.apply(Roo.bootstrap.TimeField, {
19899 cls: 'datepicker dropdown-menu',
19903 cls: 'datepicker-time',
19907 cls: 'table-condensed',
19909 Roo.bootstrap.TimeField.content,
19910 Roo.bootstrap.TimeField.footer
19929 * @class Roo.bootstrap.MonthField
19930 * @extends Roo.bootstrap.Input
19931 * Bootstrap MonthField class
19933 * @cfg {String} language default en
19936 * Create a new MonthField
19937 * @param {Object} config The config object
19940 Roo.bootstrap.MonthField = function(config){
19941 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19946 * Fires when this field show.
19947 * @param {Roo.bootstrap.MonthField} this
19948 * @param {Mixed} date The date value
19953 * Fires when this field hide.
19954 * @param {Roo.bootstrap.MonthField} this
19955 * @param {Mixed} date The date value
19960 * Fires when select a date.
19961 * @param {Roo.bootstrap.MonthField} this
19962 * @param {String} oldvalue The old value
19963 * @param {String} newvalue The new value
19969 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19971 onRender: function(ct, position)
19974 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19976 this.language = this.language || 'en';
19977 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19978 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19980 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19981 this.isInline = false;
19982 this.isInput = true;
19983 this.component = this.el.select('.add-on', true).first() || false;
19984 this.component = (this.component && this.component.length === 0) ? false : this.component;
19985 this.hasInput = this.component && this.inputEL().length;
19987 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19989 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19991 this.picker().on('mousedown', this.onMousedown, this);
19992 this.picker().on('click', this.onClick, this);
19994 this.picker().addClass('datepicker-dropdown');
19996 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19997 v.setStyle('width', '189px');
20004 if(this.isInline) {
20010 setValue: function(v, suppressEvent)
20012 var o = this.getValue();
20014 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20018 if(suppressEvent !== true){
20019 this.fireEvent('select', this, o, v);
20024 getValue: function()
20029 onClick: function(e)
20031 e.stopPropagation();
20032 e.preventDefault();
20034 var target = e.getTarget();
20036 if(target.nodeName.toLowerCase() === 'i'){
20037 target = Roo.get(target).dom.parentNode;
20040 var nodeName = target.nodeName;
20041 var className = target.className;
20042 var html = target.innerHTML;
20044 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20048 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20050 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20056 picker : function()
20058 return this.pickerEl;
20061 fillMonths: function()
20064 var months = this.picker().select('>.datepicker-months td', true).first();
20066 months.dom.innerHTML = '';
20072 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20075 months.createChild(month);
20084 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20085 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20088 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20089 e.removeClass('active');
20091 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20092 e.addClass('active');
20099 if(this.isInline) {
20103 this.picker().removeClass(['bottom', 'top']);
20105 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20107 * place to the top of element!
20111 this.picker().addClass('top');
20112 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20117 this.picker().addClass('bottom');
20119 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20122 onFocus : function()
20124 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20128 onBlur : function()
20130 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20132 var d = this.inputEl().getValue();
20141 this.picker().show();
20142 this.picker().select('>.datepicker-months', true).first().show();
20146 this.fireEvent('show', this, this.date);
20151 if(this.isInline) {
20154 this.picker().hide();
20155 this.fireEvent('hide', this, this.date);
20159 onMousedown: function(e)
20161 e.stopPropagation();
20162 e.preventDefault();
20167 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20171 fireKey: function(e)
20173 if (!this.picker().isVisible()){
20174 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20185 e.preventDefault();
20189 dir = e.keyCode == 37 ? -1 : 1;
20191 this.vIndex = this.vIndex + dir;
20193 if(this.vIndex < 0){
20197 if(this.vIndex > 11){
20201 if(isNaN(this.vIndex)){
20205 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20211 dir = e.keyCode == 38 ? -1 : 1;
20213 this.vIndex = this.vIndex + dir * 4;
20215 if(this.vIndex < 0){
20219 if(this.vIndex > 11){
20223 if(isNaN(this.vIndex)){
20227 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20232 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20233 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20237 e.preventDefault();
20240 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20241 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20257 this.picker().remove();
20262 Roo.apply(Roo.bootstrap.MonthField, {
20281 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20282 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20287 Roo.apply(Roo.bootstrap.MonthField, {
20291 cls: 'datepicker dropdown-menu roo-dynamic',
20295 cls: 'datepicker-months',
20299 cls: 'table-condensed',
20301 Roo.bootstrap.DateField.content
20321 * @class Roo.bootstrap.CheckBox
20322 * @extends Roo.bootstrap.Input
20323 * Bootstrap CheckBox class
20325 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20326 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20327 * @cfg {String} boxLabel The text that appears beside the checkbox
20328 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20329 * @cfg {Boolean} checked initnal the element
20330 * @cfg {Boolean} inline inline the element (default false)
20331 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20332 * @cfg {String} tooltip label tooltip
20335 * Create a new CheckBox
20336 * @param {Object} config The config object
20339 Roo.bootstrap.CheckBox = function(config){
20340 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20345 * Fires when the element is checked or unchecked.
20346 * @param {Roo.bootstrap.CheckBox} this This input
20347 * @param {Boolean} checked The new checked value
20352 * Fires when the element is click.
20353 * @param {Roo.bootstrap.CheckBox} this This input
20360 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20362 inputType: 'checkbox',
20371 getAutoCreate : function()
20373 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20379 cfg.cls = 'form-group ' + this.inputType; //input-group
20382 cfg.cls += ' ' + this.inputType + '-inline';
20388 type : this.inputType,
20389 value : this.inputValue,
20390 cls : 'roo-' + this.inputType, //'form-box',
20391 placeholder : this.placeholder || ''
20395 if(this.inputType != 'radio'){
20399 cls : 'roo-hidden-value',
20400 value : this.checked ? this.inputValue : this.valueOff
20405 if (this.weight) { // Validity check?
20406 cfg.cls += " " + this.inputType + "-" + this.weight;
20409 if (this.disabled) {
20410 input.disabled=true;
20414 input.checked = this.checked;
20419 input.name = this.name;
20421 if(this.inputType != 'radio'){
20422 hidden.name = this.name;
20423 input.name = '_hidden_' + this.name;
20428 input.cls += ' input-' + this.size;
20433 ['xs','sm','md','lg'].map(function(size){
20434 if (settings[size]) {
20435 cfg.cls += ' col-' + size + '-' + settings[size];
20439 var inputblock = input;
20441 if (this.before || this.after) {
20444 cls : 'input-group',
20449 inputblock.cn.push({
20451 cls : 'input-group-addon',
20456 inputblock.cn.push(input);
20458 if(this.inputType != 'radio'){
20459 inputblock.cn.push(hidden);
20463 inputblock.cn.push({
20465 cls : 'input-group-addon',
20472 if (align ==='left' && this.fieldLabel.length) {
20473 // Roo.log("left and has label");
20478 cls : 'control-label',
20479 html : this.fieldLabel
20489 if(this.labelWidth > 12){
20490 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20493 if(this.labelWidth < 13 && this.labelmd == 0){
20494 this.labelmd = this.labelWidth;
20497 if(this.labellg > 0){
20498 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20499 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20502 if(this.labelmd > 0){
20503 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20504 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20507 if(this.labelsm > 0){
20508 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20509 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20512 if(this.labelxs > 0){
20513 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20514 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20517 } else if ( this.fieldLabel.length) {
20518 // Roo.log(" label");
20522 tag: this.boxLabel ? 'span' : 'label',
20524 cls: 'control-label box-input-label',
20525 //cls : 'input-group-addon',
20526 html : this.fieldLabel
20535 // Roo.log(" no label && no align");
20536 cfg.cn = [ inputblock ] ;
20542 var boxLabelCfg = {
20544 //'for': id, // box label is handled by onclick - so no for...
20546 html: this.boxLabel
20550 boxLabelCfg.tooltip = this.tooltip;
20553 cfg.cn.push(boxLabelCfg);
20556 if(this.inputType != 'radio'){
20557 cfg.cn.push(hidden);
20565 * return the real input element.
20567 inputEl: function ()
20569 return this.el.select('input.roo-' + this.inputType,true).first();
20571 hiddenEl: function ()
20573 return this.el.select('input.roo-hidden-value',true).first();
20576 labelEl: function()
20578 return this.el.select('label.control-label',true).first();
20580 /* depricated... */
20584 return this.labelEl();
20587 boxLabelEl: function()
20589 return this.el.select('label.box-label',true).first();
20592 initEvents : function()
20594 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20596 this.inputEl().on('click', this.onClick, this);
20598 if (this.boxLabel) {
20599 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20602 this.startValue = this.getValue();
20605 Roo.bootstrap.CheckBox.register(this);
20609 onClick : function(e)
20611 if(this.fireEvent('click', this, e) !== false){
20612 this.setChecked(!this.checked);
20617 setChecked : function(state,suppressEvent)
20619 this.startValue = this.getValue();
20621 if(this.inputType == 'radio'){
20623 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20624 e.dom.checked = false;
20627 this.inputEl().dom.checked = true;
20629 this.inputEl().dom.value = this.inputValue;
20631 if(suppressEvent !== true){
20632 this.fireEvent('check', this, true);
20640 this.checked = state;
20642 this.inputEl().dom.checked = state;
20645 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20647 if(suppressEvent !== true){
20648 this.fireEvent('check', this, state);
20654 getValue : function()
20656 if(this.inputType == 'radio'){
20657 return this.getGroupValue();
20660 return this.hiddenEl().dom.value;
20664 getGroupValue : function()
20666 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20670 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20673 setValue : function(v,suppressEvent)
20675 if(this.inputType == 'radio'){
20676 this.setGroupValue(v, suppressEvent);
20680 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20685 setGroupValue : function(v, suppressEvent)
20687 this.startValue = this.getValue();
20689 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20690 e.dom.checked = false;
20692 if(e.dom.value == v){
20693 e.dom.checked = true;
20697 if(suppressEvent !== true){
20698 this.fireEvent('check', this, true);
20706 validate : function()
20708 if(this.getVisibilityEl().hasClass('hidden')){
20714 (this.inputType == 'radio' && this.validateRadio()) ||
20715 (this.inputType == 'checkbox' && this.validateCheckbox())
20721 this.markInvalid();
20725 validateRadio : function()
20727 if(this.getVisibilityEl().hasClass('hidden')){
20731 if(this.allowBlank){
20737 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20738 if(!e.dom.checked){
20750 validateCheckbox : function()
20753 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20754 //return (this.getValue() == this.inputValue) ? true : false;
20757 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20765 for(var i in group){
20766 if(group[i].el.isVisible(true)){
20774 for(var i in group){
20779 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20786 * Mark this field as valid
20788 markValid : function()
20792 this.fireEvent('valid', this);
20794 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20797 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20804 if(this.inputType == 'radio'){
20805 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20806 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20807 e.findParent('.form-group', false, true).addClass(_this.validClass);
20814 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20815 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20819 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20825 for(var i in group){
20826 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20827 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20832 * Mark this field as invalid
20833 * @param {String} msg The validation message
20835 markInvalid : function(msg)
20837 if(this.allowBlank){
20843 this.fireEvent('invalid', this, msg);
20845 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20848 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20852 label.markInvalid();
20855 if(this.inputType == 'radio'){
20856 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20857 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20858 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20865 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20866 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20870 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20876 for(var i in group){
20877 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20878 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20883 clearInvalid : function()
20885 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20887 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20889 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20891 if (label && label.iconEl) {
20892 label.iconEl.removeClass(label.validClass);
20893 label.iconEl.removeClass(label.invalidClass);
20897 disable : function()
20899 if(this.inputType != 'radio'){
20900 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20907 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20908 _this.getActionEl().addClass(this.disabledClass);
20909 e.dom.disabled = true;
20913 this.disabled = true;
20914 this.fireEvent("disable", this);
20918 enable : function()
20920 if(this.inputType != 'radio'){
20921 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20928 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20929 _this.getActionEl().removeClass(this.disabledClass);
20930 e.dom.disabled = false;
20934 this.disabled = false;
20935 this.fireEvent("enable", this);
20939 setBoxLabel : function(v)
20944 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20950 Roo.apply(Roo.bootstrap.CheckBox, {
20955 * register a CheckBox Group
20956 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20958 register : function(checkbox)
20960 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20961 this.groups[checkbox.groupId] = {};
20964 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20968 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20972 * fetch a CheckBox Group based on the group ID
20973 * @param {string} the group ID
20974 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20976 get: function(groupId) {
20977 if (typeof(this.groups[groupId]) == 'undefined') {
20981 return this.groups[groupId] ;
20994 * @class Roo.bootstrap.Radio
20995 * @extends Roo.bootstrap.Component
20996 * Bootstrap Radio class
20997 * @cfg {String} boxLabel - the label associated
20998 * @cfg {String} value - the value of radio
21001 * Create a new Radio
21002 * @param {Object} config The config object
21004 Roo.bootstrap.Radio = function(config){
21005 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21009 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21015 getAutoCreate : function()
21019 cls : 'form-group radio',
21024 html : this.boxLabel
21032 initEvents : function()
21034 this.parent().register(this);
21036 this.el.on('click', this.onClick, this);
21040 onClick : function(e)
21042 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21043 this.setChecked(true);
21047 setChecked : function(state, suppressEvent)
21049 this.parent().setValue(this.value, suppressEvent);
21053 setBoxLabel : function(v)
21058 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21073 * @class Roo.bootstrap.SecurePass
21074 * @extends Roo.bootstrap.Input
21075 * Bootstrap SecurePass class
21079 * Create a new SecurePass
21080 * @param {Object} config The config object
21083 Roo.bootstrap.SecurePass = function (config) {
21084 // these go here, so the translation tool can replace them..
21086 PwdEmpty: "Please type a password, and then retype it to confirm.",
21087 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21088 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21089 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21090 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21091 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21092 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21093 TooWeak: "Your password is Too Weak."
21095 this.meterLabel = "Password strength:";
21096 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21097 this.meterClass = [
21098 "roo-password-meter-tooweak",
21099 "roo-password-meter-weak",
21100 "roo-password-meter-medium",
21101 "roo-password-meter-strong",
21102 "roo-password-meter-grey"
21107 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21110 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21112 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21114 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21115 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21116 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21117 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21118 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21119 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21120 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21130 * @cfg {String/Object} Label for the strength meter (defaults to
21131 * 'Password strength:')
21136 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21137 * ['Weak', 'Medium', 'Strong'])
21140 pwdStrengths: false,
21153 initEvents: function ()
21155 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21157 if (this.el.is('input[type=password]') && Roo.isSafari) {
21158 this.el.on('keydown', this.SafariOnKeyDown, this);
21161 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21164 onRender: function (ct, position)
21166 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21167 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21168 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21170 this.trigger.createChild({
21175 cls: 'roo-password-meter-grey col-xs-12',
21178 //width: this.meterWidth + 'px'
21182 cls: 'roo-password-meter-text'
21188 if (this.hideTrigger) {
21189 this.trigger.setDisplayed(false);
21191 this.setSize(this.width || '', this.height || '');
21194 onDestroy: function ()
21196 if (this.trigger) {
21197 this.trigger.removeAllListeners();
21198 this.trigger.remove();
21201 this.wrap.remove();
21203 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21206 checkStrength: function ()
21208 var pwd = this.inputEl().getValue();
21209 if (pwd == this._lastPwd) {
21214 if (this.ClientSideStrongPassword(pwd)) {
21216 } else if (this.ClientSideMediumPassword(pwd)) {
21218 } else if (this.ClientSideWeakPassword(pwd)) {
21224 Roo.log('strength1: ' + strength);
21226 //var pm = this.trigger.child('div/div/div').dom;
21227 var pm = this.trigger.child('div/div');
21228 pm.removeClass(this.meterClass);
21229 pm.addClass(this.meterClass[strength]);
21232 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21234 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21236 this._lastPwd = pwd;
21240 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21242 this._lastPwd = '';
21244 var pm = this.trigger.child('div/div');
21245 pm.removeClass(this.meterClass);
21246 pm.addClass('roo-password-meter-grey');
21249 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21252 this.inputEl().dom.type='password';
21255 validateValue: function (value)
21258 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21261 if (value.length == 0) {
21262 if (this.allowBlank) {
21263 this.clearInvalid();
21267 this.markInvalid(this.errors.PwdEmpty);
21268 this.errorMsg = this.errors.PwdEmpty;
21276 if ('[\x21-\x7e]*'.match(value)) {
21277 this.markInvalid(this.errors.PwdBadChar);
21278 this.errorMsg = this.errors.PwdBadChar;
21281 if (value.length < 6) {
21282 this.markInvalid(this.errors.PwdShort);
21283 this.errorMsg = this.errors.PwdShort;
21286 if (value.length > 16) {
21287 this.markInvalid(this.errors.PwdLong);
21288 this.errorMsg = this.errors.PwdLong;
21292 if (this.ClientSideStrongPassword(value)) {
21294 } else if (this.ClientSideMediumPassword(value)) {
21296 } else if (this.ClientSideWeakPassword(value)) {
21303 if (strength < 2) {
21304 //this.markInvalid(this.errors.TooWeak);
21305 this.errorMsg = this.errors.TooWeak;
21310 console.log('strength2: ' + strength);
21312 //var pm = this.trigger.child('div/div/div').dom;
21314 var pm = this.trigger.child('div/div');
21315 pm.removeClass(this.meterClass);
21316 pm.addClass(this.meterClass[strength]);
21318 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21320 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21322 this.errorMsg = '';
21326 CharacterSetChecks: function (type)
21329 this.fResult = false;
21332 isctype: function (character, type)
21335 case this.kCapitalLetter:
21336 if (character >= 'A' && character <= 'Z') {
21341 case this.kSmallLetter:
21342 if (character >= 'a' && character <= 'z') {
21348 if (character >= '0' && character <= '9') {
21353 case this.kPunctuation:
21354 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21365 IsLongEnough: function (pwd, size)
21367 return !(pwd == null || isNaN(size) || pwd.length < size);
21370 SpansEnoughCharacterSets: function (word, nb)
21372 if (!this.IsLongEnough(word, nb))
21377 var characterSetChecks = new Array(
21378 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21379 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21382 for (var index = 0; index < word.length; ++index) {
21383 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21384 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21385 characterSetChecks[nCharSet].fResult = true;
21392 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21393 if (characterSetChecks[nCharSet].fResult) {
21398 if (nCharSets < nb) {
21404 ClientSideStrongPassword: function (pwd)
21406 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21409 ClientSideMediumPassword: function (pwd)
21411 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21414 ClientSideWeakPassword: function (pwd)
21416 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21419 })//<script type="text/javascript">
21422 * Based Ext JS Library 1.1.1
21423 * Copyright(c) 2006-2007, Ext JS, LLC.
21429 * @class Roo.HtmlEditorCore
21430 * @extends Roo.Component
21431 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21433 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21436 Roo.HtmlEditorCore = function(config){
21439 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21444 * @event initialize
21445 * Fires when the editor is fully initialized (including the iframe)
21446 * @param {Roo.HtmlEditorCore} this
21451 * Fires when the editor is first receives the focus. Any insertion must wait
21452 * until after this event.
21453 * @param {Roo.HtmlEditorCore} this
21457 * @event beforesync
21458 * Fires before the textarea is updated with content from the editor iframe. Return false
21459 * to cancel the sync.
21460 * @param {Roo.HtmlEditorCore} this
21461 * @param {String} html
21465 * @event beforepush
21466 * Fires before the iframe editor is updated with content from the textarea. Return false
21467 * to cancel the push.
21468 * @param {Roo.HtmlEditorCore} this
21469 * @param {String} html
21474 * Fires when the textarea is updated with content from the editor iframe.
21475 * @param {Roo.HtmlEditorCore} this
21476 * @param {String} html
21481 * Fires when the iframe editor is updated with content from the textarea.
21482 * @param {Roo.HtmlEditorCore} this
21483 * @param {String} html
21488 * @event editorevent
21489 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21490 * @param {Roo.HtmlEditorCore} this
21496 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21498 // defaults : white / black...
21499 this.applyBlacklists();
21506 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21510 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21516 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21521 * @cfg {Number} height (in pixels)
21525 * @cfg {Number} width (in pixels)
21530 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21533 stylesheets: false,
21538 // private properties
21539 validationEvent : false,
21541 initialized : false,
21543 sourceEditMode : false,
21544 onFocus : Roo.emptyFn,
21546 hideMode:'offsets',
21550 // blacklist + whitelisted elements..
21557 * Protected method that will not generally be called directly. It
21558 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21559 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21561 getDocMarkup : function(){
21565 // inherit styels from page...??
21566 if (this.stylesheets === false) {
21568 Roo.get(document.head).select('style').each(function(node) {
21569 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21572 Roo.get(document.head).select('link').each(function(node) {
21573 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21576 } else if (!this.stylesheets.length) {
21578 st = '<style type="text/css">' +
21579 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21582 st = '<style type="text/css">' +
21587 st += '<style type="text/css">' +
21588 'IMG { cursor: pointer } ' +
21591 var cls = 'roo-htmleditor-body';
21593 if(this.bodyCls.length){
21594 cls += ' ' + this.bodyCls;
21597 return '<html><head>' + st +
21598 //<style type="text/css">' +
21599 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21601 ' </head><body class="' + cls + '"></body></html>';
21605 onRender : function(ct, position)
21608 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21609 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21612 this.el.dom.style.border = '0 none';
21613 this.el.dom.setAttribute('tabIndex', -1);
21614 this.el.addClass('x-hidden hide');
21618 if(Roo.isIE){ // fix IE 1px bogus margin
21619 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21623 this.frameId = Roo.id();
21627 var iframe = this.owner.wrap.createChild({
21629 cls: 'form-control', // bootstrap..
21631 name: this.frameId,
21632 frameBorder : 'no',
21633 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21638 this.iframe = iframe.dom;
21640 this.assignDocWin();
21642 this.doc.designMode = 'on';
21645 this.doc.write(this.getDocMarkup());
21649 var task = { // must defer to wait for browser to be ready
21651 //console.log("run task?" + this.doc.readyState);
21652 this.assignDocWin();
21653 if(this.doc.body || this.doc.readyState == 'complete'){
21655 this.doc.designMode="on";
21659 Roo.TaskMgr.stop(task);
21660 this.initEditor.defer(10, this);
21667 Roo.TaskMgr.start(task);
21672 onResize : function(w, h)
21674 Roo.log('resize: ' +w + ',' + h );
21675 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21679 if(typeof w == 'number'){
21681 this.iframe.style.width = w + 'px';
21683 if(typeof h == 'number'){
21685 this.iframe.style.height = h + 'px';
21687 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21694 * Toggles the editor between standard and source edit mode.
21695 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21697 toggleSourceEdit : function(sourceEditMode){
21699 this.sourceEditMode = sourceEditMode === true;
21701 if(this.sourceEditMode){
21703 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21706 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21707 //this.iframe.className = '';
21710 //this.setSize(this.owner.wrap.getSize());
21711 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21718 * Protected method that will not generally be called directly. If you need/want
21719 * custom HTML cleanup, this is the method you should override.
21720 * @param {String} html The HTML to be cleaned
21721 * return {String} The cleaned HTML
21723 cleanHtml : function(html){
21724 html = String(html);
21725 if(html.length > 5){
21726 if(Roo.isSafari){ // strip safari nonsense
21727 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21730 if(html == ' '){
21737 * HTML Editor -> Textarea
21738 * Protected method that will not generally be called directly. Syncs the contents
21739 * of the editor iframe with the textarea.
21741 syncValue : function(){
21742 if(this.initialized){
21743 var bd = (this.doc.body || this.doc.documentElement);
21744 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21745 var html = bd.innerHTML;
21747 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21748 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21750 html = '<div style="'+m[0]+'">' + html + '</div>';
21753 html = this.cleanHtml(html);
21754 // fix up the special chars.. normaly like back quotes in word...
21755 // however we do not want to do this with chinese..
21756 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21757 var cc = b.charCodeAt();
21759 (cc >= 0x4E00 && cc < 0xA000 ) ||
21760 (cc >= 0x3400 && cc < 0x4E00 ) ||
21761 (cc >= 0xf900 && cc < 0xfb00 )
21767 if(this.owner.fireEvent('beforesync', this, html) !== false){
21768 this.el.dom.value = html;
21769 this.owner.fireEvent('sync', this, html);
21775 * Protected method that will not generally be called directly. Pushes the value of the textarea
21776 * into the iframe editor.
21778 pushValue : function(){
21779 if(this.initialized){
21780 var v = this.el.dom.value.trim();
21782 // if(v.length < 1){
21786 if(this.owner.fireEvent('beforepush', this, v) !== false){
21787 var d = (this.doc.body || this.doc.documentElement);
21789 this.cleanUpPaste();
21790 this.el.dom.value = d.innerHTML;
21791 this.owner.fireEvent('push', this, v);
21797 deferFocus : function(){
21798 this.focus.defer(10, this);
21802 focus : function(){
21803 if(this.win && !this.sourceEditMode){
21810 assignDocWin: function()
21812 var iframe = this.iframe;
21815 this.doc = iframe.contentWindow.document;
21816 this.win = iframe.contentWindow;
21818 // if (!Roo.get(this.frameId)) {
21821 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21822 // this.win = Roo.get(this.frameId).dom.contentWindow;
21824 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21828 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21829 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21834 initEditor : function(){
21835 //console.log("INIT EDITOR");
21836 this.assignDocWin();
21840 this.doc.designMode="on";
21842 this.doc.write(this.getDocMarkup());
21845 var dbody = (this.doc.body || this.doc.documentElement);
21846 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21847 // this copies styles from the containing element into thsi one..
21848 // not sure why we need all of this..
21849 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21851 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21852 //ss['background-attachment'] = 'fixed'; // w3c
21853 dbody.bgProperties = 'fixed'; // ie
21854 //Roo.DomHelper.applyStyles(dbody, ss);
21855 Roo.EventManager.on(this.doc, {
21856 //'mousedown': this.onEditorEvent,
21857 'mouseup': this.onEditorEvent,
21858 'dblclick': this.onEditorEvent,
21859 'click': this.onEditorEvent,
21860 'keyup': this.onEditorEvent,
21865 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21867 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21868 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21870 this.initialized = true;
21872 this.owner.fireEvent('initialize', this);
21877 onDestroy : function(){
21883 //for (var i =0; i < this.toolbars.length;i++) {
21884 // // fixme - ask toolbars for heights?
21885 // this.toolbars[i].onDestroy();
21888 //this.wrap.dom.innerHTML = '';
21889 //this.wrap.remove();
21894 onFirstFocus : function(){
21896 this.assignDocWin();
21899 this.activated = true;
21902 if(Roo.isGecko){ // prevent silly gecko errors
21904 var s = this.win.getSelection();
21905 if(!s.focusNode || s.focusNode.nodeType != 3){
21906 var r = s.getRangeAt(0);
21907 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21912 this.execCmd('useCSS', true);
21913 this.execCmd('styleWithCSS', false);
21916 this.owner.fireEvent('activate', this);
21920 adjustFont: function(btn){
21921 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21922 //if(Roo.isSafari){ // safari
21925 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21926 if(Roo.isSafari){ // safari
21927 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21928 v = (v < 10) ? 10 : v;
21929 v = (v > 48) ? 48 : v;
21930 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21935 v = Math.max(1, v+adjust);
21937 this.execCmd('FontSize', v );
21940 onEditorEvent : function(e)
21942 this.owner.fireEvent('editorevent', this, e);
21943 // this.updateToolbar();
21944 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21947 insertTag : function(tg)
21949 // could be a bit smarter... -> wrap the current selected tRoo..
21950 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21952 range = this.createRange(this.getSelection());
21953 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21954 wrappingNode.appendChild(range.extractContents());
21955 range.insertNode(wrappingNode);
21962 this.execCmd("formatblock", tg);
21966 insertText : function(txt)
21970 var range = this.createRange();
21971 range.deleteContents();
21972 //alert(Sender.getAttribute('label'));
21974 range.insertNode(this.doc.createTextNode(txt));
21980 * Executes a Midas editor command on the editor document and performs necessary focus and
21981 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21982 * @param {String} cmd The Midas command
21983 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21985 relayCmd : function(cmd, value){
21987 this.execCmd(cmd, value);
21988 this.owner.fireEvent('editorevent', this);
21989 //this.updateToolbar();
21990 this.owner.deferFocus();
21994 * Executes a Midas editor command directly on the editor document.
21995 * For visual commands, you should use {@link #relayCmd} instead.
21996 * <b>This should only be called after the editor is initialized.</b>
21997 * @param {String} cmd The Midas command
21998 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22000 execCmd : function(cmd, value){
22001 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22008 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22010 * @param {String} text | dom node..
22012 insertAtCursor : function(text)
22015 if(!this.activated){
22021 var r = this.doc.selection.createRange();
22032 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22036 // from jquery ui (MIT licenced)
22038 var win = this.win;
22040 if (win.getSelection && win.getSelection().getRangeAt) {
22041 range = win.getSelection().getRangeAt(0);
22042 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22043 range.insertNode(node);
22044 } else if (win.document.selection && win.document.selection.createRange) {
22045 // no firefox support
22046 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22047 win.document.selection.createRange().pasteHTML(txt);
22049 // no firefox support
22050 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22051 this.execCmd('InsertHTML', txt);
22060 mozKeyPress : function(e){
22062 var c = e.getCharCode(), cmd;
22065 c = String.fromCharCode(c).toLowerCase();
22079 this.cleanUpPaste.defer(100, this);
22087 e.preventDefault();
22095 fixKeys : function(){ // load time branching for fastest keydown performance
22097 return function(e){
22098 var k = e.getKey(), r;
22101 r = this.doc.selection.createRange();
22104 r.pasteHTML('    ');
22111 r = this.doc.selection.createRange();
22113 var target = r.parentElement();
22114 if(!target || target.tagName.toLowerCase() != 'li'){
22116 r.pasteHTML('<br />');
22122 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22123 this.cleanUpPaste.defer(100, this);
22129 }else if(Roo.isOpera){
22130 return function(e){
22131 var k = e.getKey();
22135 this.execCmd('InsertHTML','    ');
22138 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22139 this.cleanUpPaste.defer(100, this);
22144 }else if(Roo.isSafari){
22145 return function(e){
22146 var k = e.getKey();
22150 this.execCmd('InsertText','\t');
22154 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22155 this.cleanUpPaste.defer(100, this);
22163 getAllAncestors: function()
22165 var p = this.getSelectedNode();
22168 a.push(p); // push blank onto stack..
22169 p = this.getParentElement();
22173 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22177 a.push(this.doc.body);
22181 lastSelNode : false,
22184 getSelection : function()
22186 this.assignDocWin();
22187 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22190 getSelectedNode: function()
22192 // this may only work on Gecko!!!
22194 // should we cache this!!!!
22199 var range = this.createRange(this.getSelection()).cloneRange();
22202 var parent = range.parentElement();
22204 var testRange = range.duplicate();
22205 testRange.moveToElementText(parent);
22206 if (testRange.inRange(range)) {
22209 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22212 parent = parent.parentElement;
22217 // is ancestor a text element.
22218 var ac = range.commonAncestorContainer;
22219 if (ac.nodeType == 3) {
22220 ac = ac.parentNode;
22223 var ar = ac.childNodes;
22226 var other_nodes = [];
22227 var has_other_nodes = false;
22228 for (var i=0;i<ar.length;i++) {
22229 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22232 // fullly contained node.
22234 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22239 // probably selected..
22240 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22241 other_nodes.push(ar[i]);
22245 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22250 has_other_nodes = true;
22252 if (!nodes.length && other_nodes.length) {
22253 nodes= other_nodes;
22255 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22261 createRange: function(sel)
22263 // this has strange effects when using with
22264 // top toolbar - not sure if it's a great idea.
22265 //this.editor.contentWindow.focus();
22266 if (typeof sel != "undefined") {
22268 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22270 return this.doc.createRange();
22273 return this.doc.createRange();
22276 getParentElement: function()
22279 this.assignDocWin();
22280 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22282 var range = this.createRange(sel);
22285 var p = range.commonAncestorContainer;
22286 while (p.nodeType == 3) { // text node
22297 * Range intersection.. the hard stuff...
22301 * [ -- selected range --- ]
22305 * if end is before start or hits it. fail.
22306 * if start is after end or hits it fail.
22308 * if either hits (but other is outside. - then it's not
22314 // @see http://www.thismuchiknow.co.uk/?p=64.
22315 rangeIntersectsNode : function(range, node)
22317 var nodeRange = node.ownerDocument.createRange();
22319 nodeRange.selectNode(node);
22321 nodeRange.selectNodeContents(node);
22324 var rangeStartRange = range.cloneRange();
22325 rangeStartRange.collapse(true);
22327 var rangeEndRange = range.cloneRange();
22328 rangeEndRange.collapse(false);
22330 var nodeStartRange = nodeRange.cloneRange();
22331 nodeStartRange.collapse(true);
22333 var nodeEndRange = nodeRange.cloneRange();
22334 nodeEndRange.collapse(false);
22336 return rangeStartRange.compareBoundaryPoints(
22337 Range.START_TO_START, nodeEndRange) == -1 &&
22338 rangeEndRange.compareBoundaryPoints(
22339 Range.START_TO_START, nodeStartRange) == 1;
22343 rangeCompareNode : function(range, node)
22345 var nodeRange = node.ownerDocument.createRange();
22347 nodeRange.selectNode(node);
22349 nodeRange.selectNodeContents(node);
22353 range.collapse(true);
22355 nodeRange.collapse(true);
22357 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22358 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22360 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22362 var nodeIsBefore = ss == 1;
22363 var nodeIsAfter = ee == -1;
22365 if (nodeIsBefore && nodeIsAfter) {
22368 if (!nodeIsBefore && nodeIsAfter) {
22369 return 1; //right trailed.
22372 if (nodeIsBefore && !nodeIsAfter) {
22373 return 2; // left trailed.
22379 // private? - in a new class?
22380 cleanUpPaste : function()
22382 // cleans up the whole document..
22383 Roo.log('cleanuppaste');
22385 this.cleanUpChildren(this.doc.body);
22386 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22387 if (clean != this.doc.body.innerHTML) {
22388 this.doc.body.innerHTML = clean;
22393 cleanWordChars : function(input) {// change the chars to hex code
22394 var he = Roo.HtmlEditorCore;
22396 var output = input;
22397 Roo.each(he.swapCodes, function(sw) {
22398 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22400 output = output.replace(swapper, sw[1]);
22407 cleanUpChildren : function (n)
22409 if (!n.childNodes.length) {
22412 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22413 this.cleanUpChild(n.childNodes[i]);
22420 cleanUpChild : function (node)
22423 //console.log(node);
22424 if (node.nodeName == "#text") {
22425 // clean up silly Windows -- stuff?
22428 if (node.nodeName == "#comment") {
22429 node.parentNode.removeChild(node);
22430 // clean up silly Windows -- stuff?
22433 var lcname = node.tagName.toLowerCase();
22434 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22435 // whitelist of tags..
22437 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22439 node.parentNode.removeChild(node);
22444 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22446 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22447 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22449 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22450 // remove_keep_children = true;
22453 if (remove_keep_children) {
22454 this.cleanUpChildren(node);
22455 // inserts everything just before this node...
22456 while (node.childNodes.length) {
22457 var cn = node.childNodes[0];
22458 node.removeChild(cn);
22459 node.parentNode.insertBefore(cn, node);
22461 node.parentNode.removeChild(node);
22465 if (!node.attributes || !node.attributes.length) {
22466 this.cleanUpChildren(node);
22470 function cleanAttr(n,v)
22473 if (v.match(/^\./) || v.match(/^\//)) {
22476 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22479 if (v.match(/^#/)) {
22482 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22483 node.removeAttribute(n);
22487 var cwhite = this.cwhite;
22488 var cblack = this.cblack;
22490 function cleanStyle(n,v)
22492 if (v.match(/expression/)) { //XSS?? should we even bother..
22493 node.removeAttribute(n);
22497 var parts = v.split(/;/);
22500 Roo.each(parts, function(p) {
22501 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22505 var l = p.split(':').shift().replace(/\s+/g,'');
22506 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22508 if ( cwhite.length && cblack.indexOf(l) > -1) {
22509 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22510 //node.removeAttribute(n);
22514 // only allow 'c whitelisted system attributes'
22515 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22516 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22517 //node.removeAttribute(n);
22527 if (clean.length) {
22528 node.setAttribute(n, clean.join(';'));
22530 node.removeAttribute(n);
22536 for (var i = node.attributes.length-1; i > -1 ; i--) {
22537 var a = node.attributes[i];
22540 if (a.name.toLowerCase().substr(0,2)=='on') {
22541 node.removeAttribute(a.name);
22544 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22545 node.removeAttribute(a.name);
22548 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22549 cleanAttr(a.name,a.value); // fixme..
22552 if (a.name == 'style') {
22553 cleanStyle(a.name,a.value);
22556 /// clean up MS crap..
22557 // tecnically this should be a list of valid class'es..
22560 if (a.name == 'class') {
22561 if (a.value.match(/^Mso/)) {
22562 node.className = '';
22565 if (a.value.match(/^body$/)) {
22566 node.className = '';
22577 this.cleanUpChildren(node);
22583 * Clean up MS wordisms...
22585 cleanWord : function(node)
22590 this.cleanWord(this.doc.body);
22593 if (node.nodeName == "#text") {
22594 // clean up silly Windows -- stuff?
22597 if (node.nodeName == "#comment") {
22598 node.parentNode.removeChild(node);
22599 // clean up silly Windows -- stuff?
22603 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22604 node.parentNode.removeChild(node);
22608 // remove - but keep children..
22609 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22610 while (node.childNodes.length) {
22611 var cn = node.childNodes[0];
22612 node.removeChild(cn);
22613 node.parentNode.insertBefore(cn, node);
22615 node.parentNode.removeChild(node);
22616 this.iterateChildren(node, this.cleanWord);
22620 if (node.className.length) {
22622 var cn = node.className.split(/\W+/);
22624 Roo.each(cn, function(cls) {
22625 if (cls.match(/Mso[a-zA-Z]+/)) {
22630 node.className = cna.length ? cna.join(' ') : '';
22632 node.removeAttribute("class");
22636 if (node.hasAttribute("lang")) {
22637 node.removeAttribute("lang");
22640 if (node.hasAttribute("style")) {
22642 var styles = node.getAttribute("style").split(";");
22644 Roo.each(styles, function(s) {
22645 if (!s.match(/:/)) {
22648 var kv = s.split(":");
22649 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22652 // what ever is left... we allow.
22655 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22656 if (!nstyle.length) {
22657 node.removeAttribute('style');
22660 this.iterateChildren(node, this.cleanWord);
22666 * iterateChildren of a Node, calling fn each time, using this as the scole..
22667 * @param {DomNode} node node to iterate children of.
22668 * @param {Function} fn method of this class to call on each item.
22670 iterateChildren : function(node, fn)
22672 if (!node.childNodes.length) {
22675 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22676 fn.call(this, node.childNodes[i])
22682 * cleanTableWidths.
22684 * Quite often pasting from word etc.. results in tables with column and widths.
22685 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22688 cleanTableWidths : function(node)
22693 this.cleanTableWidths(this.doc.body);
22698 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22701 Roo.log(node.tagName);
22702 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22703 this.iterateChildren(node, this.cleanTableWidths);
22706 if (node.hasAttribute('width')) {
22707 node.removeAttribute('width');
22711 if (node.hasAttribute("style")) {
22714 var styles = node.getAttribute("style").split(";");
22716 Roo.each(styles, function(s) {
22717 if (!s.match(/:/)) {
22720 var kv = s.split(":");
22721 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22724 // what ever is left... we allow.
22727 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22728 if (!nstyle.length) {
22729 node.removeAttribute('style');
22733 this.iterateChildren(node, this.cleanTableWidths);
22741 domToHTML : function(currentElement, depth, nopadtext) {
22743 depth = depth || 0;
22744 nopadtext = nopadtext || false;
22746 if (!currentElement) {
22747 return this.domToHTML(this.doc.body);
22750 //Roo.log(currentElement);
22752 var allText = false;
22753 var nodeName = currentElement.nodeName;
22754 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22756 if (nodeName == '#text') {
22758 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22763 if (nodeName != 'BODY') {
22766 // Prints the node tagName, such as <A>, <IMG>, etc
22769 for(i = 0; i < currentElement.attributes.length;i++) {
22771 var aname = currentElement.attributes.item(i).name;
22772 if (!currentElement.attributes.item(i).value.length) {
22775 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22778 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22787 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22790 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22795 // Traverse the tree
22797 var currentElementChild = currentElement.childNodes.item(i);
22798 var allText = true;
22799 var innerHTML = '';
22801 while (currentElementChild) {
22802 // Formatting code (indent the tree so it looks nice on the screen)
22803 var nopad = nopadtext;
22804 if (lastnode == 'SPAN') {
22808 if (currentElementChild.nodeName == '#text') {
22809 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22810 toadd = nopadtext ? toadd : toadd.trim();
22811 if (!nopad && toadd.length > 80) {
22812 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22814 innerHTML += toadd;
22817 currentElementChild = currentElement.childNodes.item(i);
22823 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22825 // Recursively traverse the tree structure of the child node
22826 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22827 lastnode = currentElementChild.nodeName;
22829 currentElementChild=currentElement.childNodes.item(i);
22835 // The remaining code is mostly for formatting the tree
22836 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22841 ret+= "</"+tagName+">";
22847 applyBlacklists : function()
22849 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22850 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22854 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22855 if (b.indexOf(tag) > -1) {
22858 this.white.push(tag);
22862 Roo.each(w, function(tag) {
22863 if (b.indexOf(tag) > -1) {
22866 if (this.white.indexOf(tag) > -1) {
22869 this.white.push(tag);
22874 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22875 if (w.indexOf(tag) > -1) {
22878 this.black.push(tag);
22882 Roo.each(b, function(tag) {
22883 if (w.indexOf(tag) > -1) {
22886 if (this.black.indexOf(tag) > -1) {
22889 this.black.push(tag);
22894 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22895 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22899 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22900 if (b.indexOf(tag) > -1) {
22903 this.cwhite.push(tag);
22907 Roo.each(w, function(tag) {
22908 if (b.indexOf(tag) > -1) {
22911 if (this.cwhite.indexOf(tag) > -1) {
22914 this.cwhite.push(tag);
22919 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22920 if (w.indexOf(tag) > -1) {
22923 this.cblack.push(tag);
22927 Roo.each(b, function(tag) {
22928 if (w.indexOf(tag) > -1) {
22931 if (this.cblack.indexOf(tag) > -1) {
22934 this.cblack.push(tag);
22939 setStylesheets : function(stylesheets)
22941 if(typeof(stylesheets) == 'string'){
22942 Roo.get(this.iframe.contentDocument.head).createChild({
22944 rel : 'stylesheet',
22953 Roo.each(stylesheets, function(s) {
22958 Roo.get(_this.iframe.contentDocument.head).createChild({
22960 rel : 'stylesheet',
22969 removeStylesheets : function()
22973 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22978 setStyle : function(style)
22980 Roo.get(this.iframe.contentDocument.head).createChild({
22989 // hide stuff that is not compatible
23003 * @event specialkey
23007 * @cfg {String} fieldClass @hide
23010 * @cfg {String} focusClass @hide
23013 * @cfg {String} autoCreate @hide
23016 * @cfg {String} inputType @hide
23019 * @cfg {String} invalidClass @hide
23022 * @cfg {String} invalidText @hide
23025 * @cfg {String} msgFx @hide
23028 * @cfg {String} validateOnBlur @hide
23032 Roo.HtmlEditorCore.white = [
23033 'area', 'br', 'img', 'input', 'hr', 'wbr',
23035 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23036 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23037 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23038 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23039 'table', 'ul', 'xmp',
23041 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23044 'dir', 'menu', 'ol', 'ul', 'dl',
23050 Roo.HtmlEditorCore.black = [
23051 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23053 'base', 'basefont', 'bgsound', 'blink', 'body',
23054 'frame', 'frameset', 'head', 'html', 'ilayer',
23055 'iframe', 'layer', 'link', 'meta', 'object',
23056 'script', 'style' ,'title', 'xml' // clean later..
23058 Roo.HtmlEditorCore.clean = [
23059 'script', 'style', 'title', 'xml'
23061 Roo.HtmlEditorCore.remove = [
23066 Roo.HtmlEditorCore.ablack = [
23070 Roo.HtmlEditorCore.aclean = [
23071 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23075 Roo.HtmlEditorCore.pwhite= [
23076 'http', 'https', 'mailto'
23079 // white listed style attributes.
23080 Roo.HtmlEditorCore.cwhite= [
23081 // 'text-align', /// default is to allow most things..
23087 // black listed style attributes.
23088 Roo.HtmlEditorCore.cblack= [
23089 // 'font-size' -- this can be set by the project
23093 Roo.HtmlEditorCore.swapCodes =[
23112 * @class Roo.bootstrap.HtmlEditor
23113 * @extends Roo.bootstrap.TextArea
23114 * Bootstrap HtmlEditor class
23117 * Create a new HtmlEditor
23118 * @param {Object} config The config object
23121 Roo.bootstrap.HtmlEditor = function(config){
23122 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23123 if (!this.toolbars) {
23124 this.toolbars = [];
23127 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23130 * @event initialize
23131 * Fires when the editor is fully initialized (including the iframe)
23132 * @param {HtmlEditor} this
23137 * Fires when the editor is first receives the focus. Any insertion must wait
23138 * until after this event.
23139 * @param {HtmlEditor} this
23143 * @event beforesync
23144 * Fires before the textarea is updated with content from the editor iframe. Return false
23145 * to cancel the sync.
23146 * @param {HtmlEditor} this
23147 * @param {String} html
23151 * @event beforepush
23152 * Fires before the iframe editor is updated with content from the textarea. Return false
23153 * to cancel the push.
23154 * @param {HtmlEditor} this
23155 * @param {String} html
23160 * Fires when the textarea is updated with content from the editor iframe.
23161 * @param {HtmlEditor} this
23162 * @param {String} html
23167 * Fires when the iframe editor is updated with content from the textarea.
23168 * @param {HtmlEditor} this
23169 * @param {String} html
23173 * @event editmodechange
23174 * Fires when the editor switches edit modes
23175 * @param {HtmlEditor} this
23176 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23178 editmodechange: true,
23180 * @event editorevent
23181 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23182 * @param {HtmlEditor} this
23186 * @event firstfocus
23187 * Fires when on first focus - needed by toolbars..
23188 * @param {HtmlEditor} this
23193 * Auto save the htmlEditor value as a file into Events
23194 * @param {HtmlEditor} this
23198 * @event savedpreview
23199 * preview the saved version of htmlEditor
23200 * @param {HtmlEditor} this
23207 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23211 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23216 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23221 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23226 * @cfg {Number} height (in pixels)
23230 * @cfg {Number} width (in pixels)
23235 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23238 stylesheets: false,
23243 // private properties
23244 validationEvent : false,
23246 initialized : false,
23249 onFocus : Roo.emptyFn,
23251 hideMode:'offsets',
23253 tbContainer : false,
23257 toolbarContainer :function() {
23258 return this.wrap.select('.x-html-editor-tb',true).first();
23262 * Protected method that will not generally be called directly. It
23263 * is called when the editor creates its toolbar. Override this method if you need to
23264 * add custom toolbar buttons.
23265 * @param {HtmlEditor} editor
23267 createToolbar : function(){
23268 Roo.log('renewing');
23269 Roo.log("create toolbars");
23271 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23272 this.toolbars[0].render(this.toolbarContainer());
23276 // if (!editor.toolbars || !editor.toolbars.length) {
23277 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23280 // for (var i =0 ; i < editor.toolbars.length;i++) {
23281 // editor.toolbars[i] = Roo.factory(
23282 // typeof(editor.toolbars[i]) == 'string' ?
23283 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23284 // Roo.bootstrap.HtmlEditor);
23285 // editor.toolbars[i].init(editor);
23291 onRender : function(ct, position)
23293 // Roo.log("Call onRender: " + this.xtype);
23295 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23297 this.wrap = this.inputEl().wrap({
23298 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23301 this.editorcore.onRender(ct, position);
23303 if (this.resizable) {
23304 this.resizeEl = new Roo.Resizable(this.wrap, {
23308 minHeight : this.height,
23309 height: this.height,
23310 handles : this.resizable,
23313 resize : function(r, w, h) {
23314 _t.onResize(w,h); // -something
23320 this.createToolbar(this);
23323 if(!this.width && this.resizable){
23324 this.setSize(this.wrap.getSize());
23326 if (this.resizeEl) {
23327 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23328 // should trigger onReize..
23334 onResize : function(w, h)
23336 Roo.log('resize: ' +w + ',' + h );
23337 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23341 if(this.inputEl() ){
23342 if(typeof w == 'number'){
23343 var aw = w - this.wrap.getFrameWidth('lr');
23344 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23347 if(typeof h == 'number'){
23348 var tbh = -11; // fixme it needs to tool bar size!
23349 for (var i =0; i < this.toolbars.length;i++) {
23350 // fixme - ask toolbars for heights?
23351 tbh += this.toolbars[i].el.getHeight();
23352 //if (this.toolbars[i].footer) {
23353 // tbh += this.toolbars[i].footer.el.getHeight();
23361 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23362 ah -= 5; // knock a few pixes off for look..
23363 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23367 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23368 this.editorcore.onResize(ew,eh);
23373 * Toggles the editor between standard and source edit mode.
23374 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23376 toggleSourceEdit : function(sourceEditMode)
23378 this.editorcore.toggleSourceEdit(sourceEditMode);
23380 if(this.editorcore.sourceEditMode){
23381 Roo.log('editor - showing textarea');
23384 // Roo.log(this.syncValue());
23386 this.inputEl().removeClass(['hide', 'x-hidden']);
23387 this.inputEl().dom.removeAttribute('tabIndex');
23388 this.inputEl().focus();
23390 Roo.log('editor - hiding textarea');
23392 // Roo.log(this.pushValue());
23395 this.inputEl().addClass(['hide', 'x-hidden']);
23396 this.inputEl().dom.setAttribute('tabIndex', -1);
23397 //this.deferFocus();
23400 if(this.resizable){
23401 this.setSize(this.wrap.getSize());
23404 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23407 // private (for BoxComponent)
23408 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23410 // private (for BoxComponent)
23411 getResizeEl : function(){
23415 // private (for BoxComponent)
23416 getPositionEl : function(){
23421 initEvents : function(){
23422 this.originalValue = this.getValue();
23426 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23429 // markInvalid : Roo.emptyFn,
23431 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23434 // clearInvalid : Roo.emptyFn,
23436 setValue : function(v){
23437 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23438 this.editorcore.pushValue();
23443 deferFocus : function(){
23444 this.focus.defer(10, this);
23448 focus : function(){
23449 this.editorcore.focus();
23455 onDestroy : function(){
23461 for (var i =0; i < this.toolbars.length;i++) {
23462 // fixme - ask toolbars for heights?
23463 this.toolbars[i].onDestroy();
23466 this.wrap.dom.innerHTML = '';
23467 this.wrap.remove();
23472 onFirstFocus : function(){
23473 //Roo.log("onFirstFocus");
23474 this.editorcore.onFirstFocus();
23475 for (var i =0; i < this.toolbars.length;i++) {
23476 this.toolbars[i].onFirstFocus();
23482 syncValue : function()
23484 this.editorcore.syncValue();
23487 pushValue : function()
23489 this.editorcore.pushValue();
23493 // hide stuff that is not compatible
23507 * @event specialkey
23511 * @cfg {String} fieldClass @hide
23514 * @cfg {String} focusClass @hide
23517 * @cfg {String} autoCreate @hide
23520 * @cfg {String} inputType @hide
23523 * @cfg {String} invalidClass @hide
23526 * @cfg {String} invalidText @hide
23529 * @cfg {String} msgFx @hide
23532 * @cfg {String} validateOnBlur @hide
23541 Roo.namespace('Roo.bootstrap.htmleditor');
23543 * @class Roo.bootstrap.HtmlEditorToolbar1
23548 new Roo.bootstrap.HtmlEditor({
23551 new Roo.bootstrap.HtmlEditorToolbar1({
23552 disable : { fonts: 1 , format: 1, ..., ... , ...],
23558 * @cfg {Object} disable List of elements to disable..
23559 * @cfg {Array} btns List of additional buttons.
23563 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23566 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23569 Roo.apply(this, config);
23571 // default disabled, based on 'good practice'..
23572 this.disable = this.disable || {};
23573 Roo.applyIf(this.disable, {
23576 specialElements : true
23578 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23580 this.editor = config.editor;
23581 this.editorcore = config.editor.editorcore;
23583 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23585 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23586 // dont call parent... till later.
23588 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23593 editorcore : false,
23598 "h1","h2","h3","h4","h5","h6",
23600 "abbr", "acronym", "address", "cite", "samp", "var",
23604 onRender : function(ct, position)
23606 // Roo.log("Call onRender: " + this.xtype);
23608 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23610 this.el.dom.style.marginBottom = '0';
23612 var editorcore = this.editorcore;
23613 var editor= this.editor;
23616 var btn = function(id,cmd , toggle, handler, html){
23618 var event = toggle ? 'toggle' : 'click';
23623 xns: Roo.bootstrap,
23626 enableToggle:toggle !== false,
23628 pressed : toggle ? false : null,
23631 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23632 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23638 // var cb_box = function...
23643 xns: Roo.bootstrap,
23644 glyphicon : 'font',
23648 xns: Roo.bootstrap,
23652 Roo.each(this.formats, function(f) {
23653 style.menu.items.push({
23655 xns: Roo.bootstrap,
23656 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23661 editorcore.insertTag(this.tagname);
23668 children.push(style);
23670 btn('bold',false,true);
23671 btn('italic',false,true);
23672 btn('align-left', 'justifyleft',true);
23673 btn('align-center', 'justifycenter',true);
23674 btn('align-right' , 'justifyright',true);
23675 btn('link', false, false, function(btn) {
23676 //Roo.log("create link?");
23677 var url = prompt(this.createLinkText, this.defaultLinkValue);
23678 if(url && url != 'http:/'+'/'){
23679 this.editorcore.relayCmd('createlink', url);
23682 btn('list','insertunorderedlist',true);
23683 btn('pencil', false,true, function(btn){
23685 this.toggleSourceEdit(btn.pressed);
23688 if (this.editor.btns.length > 0) {
23689 for (var i = 0; i<this.editor.btns.length; i++) {
23690 children.push(this.editor.btns[i]);
23698 xns: Roo.bootstrap,
23703 xns: Roo.bootstrap,
23708 cog.menu.items.push({
23710 xns: Roo.bootstrap,
23711 html : Clean styles,
23716 editorcore.insertTag(this.tagname);
23725 this.xtype = 'NavSimplebar';
23727 for(var i=0;i< children.length;i++) {
23729 this.buttons.add(this.addxtypeChild(children[i]));
23733 editor.on('editorevent', this.updateToolbar, this);
23735 onBtnClick : function(id)
23737 this.editorcore.relayCmd(id);
23738 this.editorcore.focus();
23742 * Protected method that will not generally be called directly. It triggers
23743 * a toolbar update by reading the markup state of the current selection in the editor.
23745 updateToolbar: function(){
23747 if(!this.editorcore.activated){
23748 this.editor.onFirstFocus(); // is this neeed?
23752 var btns = this.buttons;
23753 var doc = this.editorcore.doc;
23754 btns.get('bold').setActive(doc.queryCommandState('bold'));
23755 btns.get('italic').setActive(doc.queryCommandState('italic'));
23756 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23758 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23759 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23760 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23762 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23763 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23766 var ans = this.editorcore.getAllAncestors();
23767 if (this.formatCombo) {
23770 var store = this.formatCombo.store;
23771 this.formatCombo.setValue("");
23772 for (var i =0; i < ans.length;i++) {
23773 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23775 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23783 // hides menus... - so this cant be on a menu...
23784 Roo.bootstrap.MenuMgr.hideAll();
23786 Roo.bootstrap.MenuMgr.hideAll();
23787 //this.editorsyncValue();
23789 onFirstFocus: function() {
23790 this.buttons.each(function(item){
23794 toggleSourceEdit : function(sourceEditMode){
23797 if(sourceEditMode){
23798 Roo.log("disabling buttons");
23799 this.buttons.each( function(item){
23800 if(item.cmd != 'pencil'){
23806 Roo.log("enabling buttons");
23807 if(this.editorcore.initialized){
23808 this.buttons.each( function(item){
23814 Roo.log("calling toggole on editor");
23815 // tell the editor that it's been pressed..
23816 this.editor.toggleSourceEdit(sourceEditMode);
23826 * @class Roo.bootstrap.Table.AbstractSelectionModel
23827 * @extends Roo.util.Observable
23828 * Abstract base class for grid SelectionModels. It provides the interface that should be
23829 * implemented by descendant classes. This class should not be directly instantiated.
23832 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23833 this.locked = false;
23834 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23838 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23839 /** @ignore Called by the grid automatically. Do not call directly. */
23840 init : function(grid){
23846 * Locks the selections.
23849 this.locked = true;
23853 * Unlocks the selections.
23855 unlock : function(){
23856 this.locked = false;
23860 * Returns true if the selections are locked.
23861 * @return {Boolean}
23863 isLocked : function(){
23864 return this.locked;
23868 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23869 * @class Roo.bootstrap.Table.RowSelectionModel
23870 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23871 * It supports multiple selections and keyboard selection/navigation.
23873 * @param {Object} config
23876 Roo.bootstrap.Table.RowSelectionModel = function(config){
23877 Roo.apply(this, config);
23878 this.selections = new Roo.util.MixedCollection(false, function(o){
23883 this.lastActive = false;
23887 * @event selectionchange
23888 * Fires when the selection changes
23889 * @param {SelectionModel} this
23891 "selectionchange" : true,
23893 * @event afterselectionchange
23894 * Fires after the selection changes (eg. by key press or clicking)
23895 * @param {SelectionModel} this
23897 "afterselectionchange" : true,
23899 * @event beforerowselect
23900 * Fires when a row is selected being selected, return false to cancel.
23901 * @param {SelectionModel} this
23902 * @param {Number} rowIndex The selected index
23903 * @param {Boolean} keepExisting False if other selections will be cleared
23905 "beforerowselect" : true,
23908 * Fires when a row is selected.
23909 * @param {SelectionModel} this
23910 * @param {Number} rowIndex The selected index
23911 * @param {Roo.data.Record} r The record
23913 "rowselect" : true,
23915 * @event rowdeselect
23916 * Fires when a row is deselected.
23917 * @param {SelectionModel} this
23918 * @param {Number} rowIndex The selected index
23920 "rowdeselect" : true
23922 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23923 this.locked = false;
23926 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23928 * @cfg {Boolean} singleSelect
23929 * True to allow selection of only one row at a time (defaults to false)
23931 singleSelect : false,
23934 initEvents : function()
23937 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23938 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23939 //}else{ // allow click to work like normal
23940 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23942 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23943 this.grid.on("rowclick", this.handleMouseDown, this);
23945 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23946 "up" : function(e){
23948 this.selectPrevious(e.shiftKey);
23949 }else if(this.last !== false && this.lastActive !== false){
23950 var last = this.last;
23951 this.selectRange(this.last, this.lastActive-1);
23952 this.grid.getView().focusRow(this.lastActive);
23953 if(last !== false){
23957 this.selectFirstRow();
23959 this.fireEvent("afterselectionchange", this);
23961 "down" : function(e){
23963 this.selectNext(e.shiftKey);
23964 }else if(this.last !== false && this.lastActive !== false){
23965 var last = this.last;
23966 this.selectRange(this.last, this.lastActive+1);
23967 this.grid.getView().focusRow(this.lastActive);
23968 if(last !== false){
23972 this.selectFirstRow();
23974 this.fireEvent("afterselectionchange", this);
23978 this.grid.store.on('load', function(){
23979 this.selections.clear();
23982 var view = this.grid.view;
23983 view.on("refresh", this.onRefresh, this);
23984 view.on("rowupdated", this.onRowUpdated, this);
23985 view.on("rowremoved", this.onRemove, this);
23990 onRefresh : function()
23992 var ds = this.grid.store, i, v = this.grid.view;
23993 var s = this.selections;
23994 s.each(function(r){
23995 if((i = ds.indexOfId(r.id)) != -1){
24004 onRemove : function(v, index, r){
24005 this.selections.remove(r);
24009 onRowUpdated : function(v, index, r){
24010 if(this.isSelected(r)){
24011 v.onRowSelect(index);
24017 * @param {Array} records The records to select
24018 * @param {Boolean} keepExisting (optional) True to keep existing selections
24020 selectRecords : function(records, keepExisting)
24023 this.clearSelections();
24025 var ds = this.grid.store;
24026 for(var i = 0, len = records.length; i < len; i++){
24027 this.selectRow(ds.indexOf(records[i]), true);
24032 * Gets the number of selected rows.
24035 getCount : function(){
24036 return this.selections.length;
24040 * Selects the first row in the grid.
24042 selectFirstRow : function(){
24047 * Select the last row.
24048 * @param {Boolean} keepExisting (optional) True to keep existing selections
24050 selectLastRow : function(keepExisting){
24051 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24052 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24056 * Selects the row immediately following the last selected row.
24057 * @param {Boolean} keepExisting (optional) True to keep existing selections
24059 selectNext : function(keepExisting)
24061 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24062 this.selectRow(this.last+1, keepExisting);
24063 this.grid.getView().focusRow(this.last);
24068 * Selects the row that precedes the last selected row.
24069 * @param {Boolean} keepExisting (optional) True to keep existing selections
24071 selectPrevious : function(keepExisting){
24073 this.selectRow(this.last-1, keepExisting);
24074 this.grid.getView().focusRow(this.last);
24079 * Returns the selected records
24080 * @return {Array} Array of selected records
24082 getSelections : function(){
24083 return [].concat(this.selections.items);
24087 * Returns the first selected record.
24090 getSelected : function(){
24091 return this.selections.itemAt(0);
24096 * Clears all selections.
24098 clearSelections : function(fast)
24104 var ds = this.grid.store;
24105 var s = this.selections;
24106 s.each(function(r){
24107 this.deselectRow(ds.indexOfId(r.id));
24111 this.selections.clear();
24118 * Selects all rows.
24120 selectAll : function(){
24124 this.selections.clear();
24125 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24126 this.selectRow(i, true);
24131 * Returns True if there is a selection.
24132 * @return {Boolean}
24134 hasSelection : function(){
24135 return this.selections.length > 0;
24139 * Returns True if the specified row is selected.
24140 * @param {Number/Record} record The record or index of the record to check
24141 * @return {Boolean}
24143 isSelected : function(index){
24144 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24145 return (r && this.selections.key(r.id) ? true : false);
24149 * Returns True if the specified record id is selected.
24150 * @param {String} id The id of record to check
24151 * @return {Boolean}
24153 isIdSelected : function(id){
24154 return (this.selections.key(id) ? true : false);
24159 handleMouseDBClick : function(e, t){
24163 handleMouseDown : function(e, t)
24165 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24166 if(this.isLocked() || rowIndex < 0 ){
24169 if(e.shiftKey && this.last !== false){
24170 var last = this.last;
24171 this.selectRange(last, rowIndex, e.ctrlKey);
24172 this.last = last; // reset the last
24176 var isSelected = this.isSelected(rowIndex);
24177 //Roo.log("select row:" + rowIndex);
24179 this.deselectRow(rowIndex);
24181 this.selectRow(rowIndex, true);
24185 if(e.button !== 0 && isSelected){
24186 alert('rowIndex 2: ' + rowIndex);
24187 view.focusRow(rowIndex);
24188 }else if(e.ctrlKey && isSelected){
24189 this.deselectRow(rowIndex);
24190 }else if(!isSelected){
24191 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24192 view.focusRow(rowIndex);
24196 this.fireEvent("afterselectionchange", this);
24199 handleDragableRowClick : function(grid, rowIndex, e)
24201 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24202 this.selectRow(rowIndex, false);
24203 grid.view.focusRow(rowIndex);
24204 this.fireEvent("afterselectionchange", this);
24209 * Selects multiple rows.
24210 * @param {Array} rows Array of the indexes of the row to select
24211 * @param {Boolean} keepExisting (optional) True to keep existing selections
24213 selectRows : function(rows, keepExisting){
24215 this.clearSelections();
24217 for(var i = 0, len = rows.length; i < len; i++){
24218 this.selectRow(rows[i], true);
24223 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24224 * @param {Number} startRow The index of the first row in the range
24225 * @param {Number} endRow The index of the last row in the range
24226 * @param {Boolean} keepExisting (optional) True to retain existing selections
24228 selectRange : function(startRow, endRow, keepExisting){
24233 this.clearSelections();
24235 if(startRow <= endRow){
24236 for(var i = startRow; i <= endRow; i++){
24237 this.selectRow(i, true);
24240 for(var i = startRow; i >= endRow; i--){
24241 this.selectRow(i, true);
24247 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24248 * @param {Number} startRow The index of the first row in the range
24249 * @param {Number} endRow The index of the last row in the range
24251 deselectRange : function(startRow, endRow, preventViewNotify){
24255 for(var i = startRow; i <= endRow; i++){
24256 this.deselectRow(i, preventViewNotify);
24262 * @param {Number} row The index of the row to select
24263 * @param {Boolean} keepExisting (optional) True to keep existing selections
24265 selectRow : function(index, keepExisting, preventViewNotify)
24267 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24270 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24271 if(!keepExisting || this.singleSelect){
24272 this.clearSelections();
24275 var r = this.grid.store.getAt(index);
24276 //console.log('selectRow - record id :' + r.id);
24278 this.selections.add(r);
24279 this.last = this.lastActive = index;
24280 if(!preventViewNotify){
24281 var proxy = new Roo.Element(
24282 this.grid.getRowDom(index)
24284 proxy.addClass('bg-info info');
24286 this.fireEvent("rowselect", this, index, r);
24287 this.fireEvent("selectionchange", this);
24293 * @param {Number} row The index of the row to deselect
24295 deselectRow : function(index, preventViewNotify)
24300 if(this.last == index){
24303 if(this.lastActive == index){
24304 this.lastActive = false;
24307 var r = this.grid.store.getAt(index);
24312 this.selections.remove(r);
24313 //.console.log('deselectRow - record id :' + r.id);
24314 if(!preventViewNotify){
24316 var proxy = new Roo.Element(
24317 this.grid.getRowDom(index)
24319 proxy.removeClass('bg-info info');
24321 this.fireEvent("rowdeselect", this, index);
24322 this.fireEvent("selectionchange", this);
24326 restoreLast : function(){
24328 this.last = this._last;
24333 acceptsNav : function(row, col, cm){
24334 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24338 onEditorKey : function(field, e){
24339 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24344 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24346 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24348 }else if(k == e.ENTER && !e.ctrlKey){
24352 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24354 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24356 }else if(k == e.ESC){
24360 g.startEditing(newCell[0], newCell[1]);
24366 * Ext JS Library 1.1.1
24367 * Copyright(c) 2006-2007, Ext JS, LLC.
24369 * Originally Released Under LGPL - original licence link has changed is not relivant.
24372 * <script type="text/javascript">
24376 * @class Roo.bootstrap.PagingToolbar
24377 * @extends Roo.bootstrap.NavSimplebar
24378 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24380 * Create a new PagingToolbar
24381 * @param {Object} config The config object
24382 * @param {Roo.data.Store} store
24384 Roo.bootstrap.PagingToolbar = function(config)
24386 // old args format still supported... - xtype is prefered..
24387 // created from xtype...
24389 this.ds = config.dataSource;
24391 if (config.store && !this.ds) {
24392 this.store= Roo.factory(config.store, Roo.data);
24393 this.ds = this.store;
24394 this.ds.xmodule = this.xmodule || false;
24397 this.toolbarItems = [];
24398 if (config.items) {
24399 this.toolbarItems = config.items;
24402 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24407 this.bind(this.ds);
24410 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24414 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24416 * @cfg {Roo.data.Store} dataSource
24417 * The underlying data store providing the paged data
24420 * @cfg {String/HTMLElement/Element} container
24421 * container The id or element that will contain the toolbar
24424 * @cfg {Boolean} displayInfo
24425 * True to display the displayMsg (defaults to false)
24428 * @cfg {Number} pageSize
24429 * The number of records to display per page (defaults to 20)
24433 * @cfg {String} displayMsg
24434 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24436 displayMsg : 'Displaying {0} - {1} of {2}',
24438 * @cfg {String} emptyMsg
24439 * The message to display when no records are found (defaults to "No data to display")
24441 emptyMsg : 'No data to display',
24443 * Customizable piece of the default paging text (defaults to "Page")
24446 beforePageText : "Page",
24448 * Customizable piece of the default paging text (defaults to "of %0")
24451 afterPageText : "of {0}",
24453 * Customizable piece of the default paging text (defaults to "First Page")
24456 firstText : "First Page",
24458 * Customizable piece of the default paging text (defaults to "Previous Page")
24461 prevText : "Previous Page",
24463 * Customizable piece of the default paging text (defaults to "Next Page")
24466 nextText : "Next Page",
24468 * Customizable piece of the default paging text (defaults to "Last Page")
24471 lastText : "Last Page",
24473 * Customizable piece of the default paging text (defaults to "Refresh")
24476 refreshText : "Refresh",
24480 onRender : function(ct, position)
24482 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24483 this.navgroup.parentId = this.id;
24484 this.navgroup.onRender(this.el, null);
24485 // add the buttons to the navgroup
24487 if(this.displayInfo){
24488 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24489 this.displayEl = this.el.select('.x-paging-info', true).first();
24490 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24491 // this.displayEl = navel.el.select('span',true).first();
24497 Roo.each(_this.buttons, function(e){ // this might need to use render????
24498 Roo.factory(e).onRender(_this.el, null);
24502 Roo.each(_this.toolbarItems, function(e) {
24503 _this.navgroup.addItem(e);
24507 this.first = this.navgroup.addItem({
24508 tooltip: this.firstText,
24510 icon : 'fa fa-backward',
24512 preventDefault: true,
24513 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24516 this.prev = this.navgroup.addItem({
24517 tooltip: this.prevText,
24519 icon : 'fa fa-step-backward',
24521 preventDefault: true,
24522 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24524 //this.addSeparator();
24527 var field = this.navgroup.addItem( {
24529 cls : 'x-paging-position',
24531 html : this.beforePageText +
24532 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24533 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24536 this.field = field.el.select('input', true).first();
24537 this.field.on("keydown", this.onPagingKeydown, this);
24538 this.field.on("focus", function(){this.dom.select();});
24541 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24542 //this.field.setHeight(18);
24543 //this.addSeparator();
24544 this.next = this.navgroup.addItem({
24545 tooltip: this.nextText,
24547 html : ' <i class="fa fa-step-forward">',
24549 preventDefault: true,
24550 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24552 this.last = this.navgroup.addItem({
24553 tooltip: this.lastText,
24554 icon : 'fa fa-forward',
24557 preventDefault: true,
24558 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24560 //this.addSeparator();
24561 this.loading = this.navgroup.addItem({
24562 tooltip: this.refreshText,
24563 icon: 'fa fa-refresh',
24564 preventDefault: true,
24565 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24571 updateInfo : function(){
24572 if(this.displayEl){
24573 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24574 var msg = count == 0 ?
24578 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24580 this.displayEl.update(msg);
24585 onLoad : function(ds, r, o)
24587 this.cursor = o.params.start ? o.params.start : 0;
24589 var d = this.getPageData(),
24594 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24595 this.field.dom.value = ap;
24596 this.first.setDisabled(ap == 1);
24597 this.prev.setDisabled(ap == 1);
24598 this.next.setDisabled(ap == ps);
24599 this.last.setDisabled(ap == ps);
24600 this.loading.enable();
24605 getPageData : function(){
24606 var total = this.ds.getTotalCount();
24609 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24610 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24615 onLoadError : function(){
24616 this.loading.enable();
24620 onPagingKeydown : function(e){
24621 var k = e.getKey();
24622 var d = this.getPageData();
24624 var v = this.field.dom.value, pageNum;
24625 if(!v || isNaN(pageNum = parseInt(v, 10))){
24626 this.field.dom.value = d.activePage;
24629 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24630 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24633 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))
24635 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24636 this.field.dom.value = pageNum;
24637 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24640 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24642 var v = this.field.dom.value, pageNum;
24643 var increment = (e.shiftKey) ? 10 : 1;
24644 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24647 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24648 this.field.dom.value = d.activePage;
24651 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24653 this.field.dom.value = parseInt(v, 10) + increment;
24654 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24655 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24662 beforeLoad : function(){
24664 this.loading.disable();
24669 onClick : function(which){
24678 ds.load({params:{start: 0, limit: this.pageSize}});
24681 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24684 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24687 var total = ds.getTotalCount();
24688 var extra = total % this.pageSize;
24689 var lastStart = extra ? (total - extra) : total-this.pageSize;
24690 ds.load({params:{start: lastStart, limit: this.pageSize}});
24693 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24699 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24700 * @param {Roo.data.Store} store The data store to unbind
24702 unbind : function(ds){
24703 ds.un("beforeload", this.beforeLoad, this);
24704 ds.un("load", this.onLoad, this);
24705 ds.un("loadexception", this.onLoadError, this);
24706 ds.un("remove", this.updateInfo, this);
24707 ds.un("add", this.updateInfo, this);
24708 this.ds = undefined;
24712 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24713 * @param {Roo.data.Store} store The data store to bind
24715 bind : function(ds){
24716 ds.on("beforeload", this.beforeLoad, this);
24717 ds.on("load", this.onLoad, this);
24718 ds.on("loadexception", this.onLoadError, this);
24719 ds.on("remove", this.updateInfo, this);
24720 ds.on("add", this.updateInfo, this);
24731 * @class Roo.bootstrap.MessageBar
24732 * @extends Roo.bootstrap.Component
24733 * Bootstrap MessageBar class
24734 * @cfg {String} html contents of the MessageBar
24735 * @cfg {String} weight (info | success | warning | danger) default info
24736 * @cfg {String} beforeClass insert the bar before the given class
24737 * @cfg {Boolean} closable (true | false) default false
24738 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24741 * Create a new Element
24742 * @param {Object} config The config object
24745 Roo.bootstrap.MessageBar = function(config){
24746 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24749 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24755 beforeClass: 'bootstrap-sticky-wrap',
24757 getAutoCreate : function(){
24761 cls: 'alert alert-dismissable alert-' + this.weight,
24766 html: this.html || ''
24772 cfg.cls += ' alert-messages-fixed';
24786 onRender : function(ct, position)
24788 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24791 var cfg = Roo.apply({}, this.getAutoCreate());
24795 cfg.cls += ' ' + this.cls;
24798 cfg.style = this.style;
24800 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24802 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24805 this.el.select('>button.close').on('click', this.hide, this);
24811 if (!this.rendered) {
24817 this.fireEvent('show', this);
24823 if (!this.rendered) {
24829 this.fireEvent('hide', this);
24832 update : function()
24834 // var e = this.el.dom.firstChild;
24836 // if(this.closable){
24837 // e = e.nextSibling;
24840 // e.data = this.html || '';
24842 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24858 * @class Roo.bootstrap.Graph
24859 * @extends Roo.bootstrap.Component
24860 * Bootstrap Graph class
24864 @cfg {String} graphtype bar | vbar | pie
24865 @cfg {number} g_x coodinator | centre x (pie)
24866 @cfg {number} g_y coodinator | centre y (pie)
24867 @cfg {number} g_r radius (pie)
24868 @cfg {number} g_height height of the chart (respected by all elements in the set)
24869 @cfg {number} g_width width of the chart (respected by all elements in the set)
24870 @cfg {Object} title The title of the chart
24873 -opts (object) options for the chart
24875 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24876 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24878 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.
24879 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24881 o stretch (boolean)
24883 -opts (object) options for the pie
24886 o startAngle (number)
24887 o endAngle (number)
24891 * Create a new Input
24892 * @param {Object} config The config object
24895 Roo.bootstrap.Graph = function(config){
24896 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24902 * The img click event for the img.
24903 * @param {Roo.EventObject} e
24909 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24920 //g_colors: this.colors,
24927 getAutoCreate : function(){
24938 onRender : function(ct,position){
24941 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24943 if (typeof(Raphael) == 'undefined') {
24944 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24948 this.raphael = Raphael(this.el.dom);
24950 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24951 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24952 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24953 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24955 r.text(160, 10, "Single Series Chart").attr(txtattr);
24956 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24957 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24958 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24960 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24961 r.barchart(330, 10, 300, 220, data1);
24962 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24963 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24966 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24967 // r.barchart(30, 30, 560, 250, xdata, {
24968 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24969 // axis : "0 0 1 1",
24970 // axisxlabels : xdata
24971 // //yvalues : cols,
24974 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24976 // this.load(null,xdata,{
24977 // axis : "0 0 1 1",
24978 // axisxlabels : xdata
24983 load : function(graphtype,xdata,opts)
24985 this.raphael.clear();
24987 graphtype = this.graphtype;
24992 var r = this.raphael,
24993 fin = function () {
24994 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24996 fout = function () {
24997 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
24999 pfin = function() {
25000 this.sector.stop();
25001 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25004 this.label[0].stop();
25005 this.label[0].attr({ r: 7.5 });
25006 this.label[1].attr({ "font-weight": 800 });
25009 pfout = function() {
25010 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25013 this.label[0].animate({ r: 5 }, 500, "bounce");
25014 this.label[1].attr({ "font-weight": 400 });
25020 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25023 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25026 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25027 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25029 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25036 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25041 setTitle: function(o)
25046 initEvents: function() {
25049 this.el.on('click', this.onClick, this);
25053 onClick : function(e)
25055 Roo.log('img onclick');
25056 this.fireEvent('click', this, e);
25068 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25071 * @class Roo.bootstrap.dash.NumberBox
25072 * @extends Roo.bootstrap.Component
25073 * Bootstrap NumberBox class
25074 * @cfg {String} headline Box headline
25075 * @cfg {String} content Box content
25076 * @cfg {String} icon Box icon
25077 * @cfg {String} footer Footer text
25078 * @cfg {String} fhref Footer href
25081 * Create a new NumberBox
25082 * @param {Object} config The config object
25086 Roo.bootstrap.dash.NumberBox = function(config){
25087 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25091 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25100 getAutoCreate : function(){
25104 cls : 'small-box ',
25112 cls : 'roo-headline',
25113 html : this.headline
25117 cls : 'roo-content',
25118 html : this.content
25132 cls : 'ion ' + this.icon
25141 cls : 'small-box-footer',
25142 href : this.fhref || '#',
25146 cfg.cn.push(footer);
25153 onRender : function(ct,position){
25154 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25161 setHeadline: function (value)
25163 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25166 setFooter: function (value, href)
25168 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25171 this.el.select('a.small-box-footer',true).first().attr('href', href);
25176 setContent: function (value)
25178 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25181 initEvents: function()
25195 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25198 * @class Roo.bootstrap.dash.TabBox
25199 * @extends Roo.bootstrap.Component
25200 * Bootstrap TabBox class
25201 * @cfg {String} title Title of the TabBox
25202 * @cfg {String} icon Icon of the TabBox
25203 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25204 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25207 * Create a new TabBox
25208 * @param {Object} config The config object
25212 Roo.bootstrap.dash.TabBox = function(config){
25213 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25218 * When a pane is added
25219 * @param {Roo.bootstrap.dash.TabPane} pane
25223 * @event activatepane
25224 * When a pane is activated
25225 * @param {Roo.bootstrap.dash.TabPane} pane
25227 "activatepane" : true
25235 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25240 tabScrollable : false,
25242 getChildContainer : function()
25244 return this.el.select('.tab-content', true).first();
25247 getAutoCreate : function(){
25251 cls: 'pull-left header',
25259 cls: 'fa ' + this.icon
25265 cls: 'nav nav-tabs pull-right',
25271 if(this.tabScrollable){
25278 cls: 'nav nav-tabs pull-right',
25289 cls: 'nav-tabs-custom',
25294 cls: 'tab-content no-padding',
25302 initEvents : function()
25304 //Roo.log('add add pane handler');
25305 this.on('addpane', this.onAddPane, this);
25308 * Updates the box title
25309 * @param {String} html to set the title to.
25311 setTitle : function(value)
25313 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25315 onAddPane : function(pane)
25317 this.panes.push(pane);
25318 //Roo.log('addpane');
25320 // tabs are rendere left to right..
25321 if(!this.showtabs){
25325 var ctr = this.el.select('.nav-tabs', true).first();
25328 var existing = ctr.select('.nav-tab',true);
25329 var qty = existing.getCount();;
25332 var tab = ctr.createChild({
25334 cls : 'nav-tab' + (qty ? '' : ' active'),
25342 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25345 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25347 pane.el.addClass('active');
25352 onTabClick : function(ev,un,ob,pane)
25354 //Roo.log('tab - prev default');
25355 ev.preventDefault();
25358 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25359 pane.tab.addClass('active');
25360 //Roo.log(pane.title);
25361 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25362 // technically we should have a deactivate event.. but maybe add later.
25363 // and it should not de-activate the selected tab...
25364 this.fireEvent('activatepane', pane);
25365 pane.el.addClass('active');
25366 pane.fireEvent('activate');
25371 getActivePane : function()
25374 Roo.each(this.panes, function(p) {
25375 if(p.el.hasClass('active')){
25396 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25398 * @class Roo.bootstrap.TabPane
25399 * @extends Roo.bootstrap.Component
25400 * Bootstrap TabPane class
25401 * @cfg {Boolean} active (false | true) Default false
25402 * @cfg {String} title title of panel
25406 * Create a new TabPane
25407 * @param {Object} config The config object
25410 Roo.bootstrap.dash.TabPane = function(config){
25411 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25417 * When a pane is activated
25418 * @param {Roo.bootstrap.dash.TabPane} pane
25425 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25430 // the tabBox that this is attached to.
25433 getAutoCreate : function()
25441 cfg.cls += ' active';
25446 initEvents : function()
25448 //Roo.log('trigger add pane handler');
25449 this.parent().fireEvent('addpane', this)
25453 * Updates the tab title
25454 * @param {String} html to set the title to.
25456 setTitle: function(str)
25462 this.tab.select('a', true).first().dom.innerHTML = str;
25479 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25482 * @class Roo.bootstrap.menu.Menu
25483 * @extends Roo.bootstrap.Component
25484 * Bootstrap Menu class - container for Menu
25485 * @cfg {String} html Text of the menu
25486 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25487 * @cfg {String} icon Font awesome icon
25488 * @cfg {String} pos Menu align to (top | bottom) default bottom
25492 * Create a new Menu
25493 * @param {Object} config The config object
25497 Roo.bootstrap.menu.Menu = function(config){
25498 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25502 * @event beforeshow
25503 * Fires before this menu is displayed
25504 * @param {Roo.bootstrap.menu.Menu} this
25508 * @event beforehide
25509 * Fires before this menu is hidden
25510 * @param {Roo.bootstrap.menu.Menu} this
25515 * Fires after this menu is displayed
25516 * @param {Roo.bootstrap.menu.Menu} this
25521 * Fires after this menu is hidden
25522 * @param {Roo.bootstrap.menu.Menu} this
25527 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25528 * @param {Roo.bootstrap.menu.Menu} this
25529 * @param {Roo.EventObject} e
25536 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25540 weight : 'default',
25545 getChildContainer : function() {
25546 if(this.isSubMenu){
25550 return this.el.select('ul.dropdown-menu', true).first();
25553 getAutoCreate : function()
25558 cls : 'roo-menu-text',
25566 cls : 'fa ' + this.icon
25577 cls : 'dropdown-button btn btn-' + this.weight,
25582 cls : 'dropdown-toggle btn btn-' + this.weight,
25592 cls : 'dropdown-menu'
25598 if(this.pos == 'top'){
25599 cfg.cls += ' dropup';
25602 if(this.isSubMenu){
25605 cls : 'dropdown-menu'
25612 onRender : function(ct, position)
25614 this.isSubMenu = ct.hasClass('dropdown-submenu');
25616 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25619 initEvents : function()
25621 if(this.isSubMenu){
25625 this.hidden = true;
25627 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25628 this.triggerEl.on('click', this.onTriggerPress, this);
25630 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25631 this.buttonEl.on('click', this.onClick, this);
25637 if(this.isSubMenu){
25641 return this.el.select('ul.dropdown-menu', true).first();
25644 onClick : function(e)
25646 this.fireEvent("click", this, e);
25649 onTriggerPress : function(e)
25651 if (this.isVisible()) {
25658 isVisible : function(){
25659 return !this.hidden;
25664 this.fireEvent("beforeshow", this);
25666 this.hidden = false;
25667 this.el.addClass('open');
25669 Roo.get(document).on("mouseup", this.onMouseUp, this);
25671 this.fireEvent("show", this);
25678 this.fireEvent("beforehide", this);
25680 this.hidden = true;
25681 this.el.removeClass('open');
25683 Roo.get(document).un("mouseup", this.onMouseUp);
25685 this.fireEvent("hide", this);
25688 onMouseUp : function()
25702 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25705 * @class Roo.bootstrap.menu.Item
25706 * @extends Roo.bootstrap.Component
25707 * Bootstrap MenuItem class
25708 * @cfg {Boolean} submenu (true | false) default false
25709 * @cfg {String} html text of the item
25710 * @cfg {String} href the link
25711 * @cfg {Boolean} disable (true | false) default false
25712 * @cfg {Boolean} preventDefault (true | false) default true
25713 * @cfg {String} icon Font awesome icon
25714 * @cfg {String} pos Submenu align to (left | right) default right
25718 * Create a new Item
25719 * @param {Object} config The config object
25723 Roo.bootstrap.menu.Item = function(config){
25724 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25728 * Fires when the mouse is hovering over this menu
25729 * @param {Roo.bootstrap.menu.Item} this
25730 * @param {Roo.EventObject} e
25735 * Fires when the mouse exits this menu
25736 * @param {Roo.bootstrap.menu.Item} this
25737 * @param {Roo.EventObject} e
25743 * The raw click event for the entire grid.
25744 * @param {Roo.EventObject} e
25750 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25755 preventDefault: true,
25760 getAutoCreate : function()
25765 cls : 'roo-menu-item-text',
25773 cls : 'fa ' + this.icon
25782 href : this.href || '#',
25789 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25793 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25795 if(this.pos == 'left'){
25796 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25803 initEvents : function()
25805 this.el.on('mouseover', this.onMouseOver, this);
25806 this.el.on('mouseout', this.onMouseOut, this);
25808 this.el.select('a', true).first().on('click', this.onClick, this);
25812 onClick : function(e)
25814 if(this.preventDefault){
25815 e.preventDefault();
25818 this.fireEvent("click", this, e);
25821 onMouseOver : function(e)
25823 if(this.submenu && this.pos == 'left'){
25824 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25827 this.fireEvent("mouseover", this, e);
25830 onMouseOut : function(e)
25832 this.fireEvent("mouseout", this, e);
25844 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25847 * @class Roo.bootstrap.menu.Separator
25848 * @extends Roo.bootstrap.Component
25849 * Bootstrap Separator class
25852 * Create a new Separator
25853 * @param {Object} config The config object
25857 Roo.bootstrap.menu.Separator = function(config){
25858 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25861 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25863 getAutoCreate : function(){
25884 * @class Roo.bootstrap.Tooltip
25885 * Bootstrap Tooltip class
25886 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25887 * to determine which dom element triggers the tooltip.
25889 * It needs to add support for additional attributes like tooltip-position
25892 * Create a new Toolti
25893 * @param {Object} config The config object
25896 Roo.bootstrap.Tooltip = function(config){
25897 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25899 this.alignment = Roo.bootstrap.Tooltip.alignment;
25901 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25902 this.alignment = config.alignment;
25907 Roo.apply(Roo.bootstrap.Tooltip, {
25909 * @function init initialize tooltip monitoring.
25913 currentTip : false,
25914 currentRegion : false,
25920 Roo.get(document).on('mouseover', this.enter ,this);
25921 Roo.get(document).on('mouseout', this.leave, this);
25924 this.currentTip = new Roo.bootstrap.Tooltip();
25927 enter : function(ev)
25929 var dom = ev.getTarget();
25931 //Roo.log(['enter',dom]);
25932 var el = Roo.fly(dom);
25933 if (this.currentEl) {
25935 //Roo.log(this.currentEl);
25936 //Roo.log(this.currentEl.contains(dom));
25937 if (this.currentEl == el) {
25940 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25946 if (this.currentTip.el) {
25947 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25951 if(!el || el.dom == document){
25957 // you can not look for children, as if el is the body.. then everythign is the child..
25958 if (!el.attr('tooltip')) { //
25959 if (!el.select("[tooltip]").elements.length) {
25962 // is the mouse over this child...?
25963 bindEl = el.select("[tooltip]").first();
25964 var xy = ev.getXY();
25965 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25966 //Roo.log("not in region.");
25969 //Roo.log("child element over..");
25972 this.currentEl = bindEl;
25973 this.currentTip.bind(bindEl);
25974 this.currentRegion = Roo.lib.Region.getRegion(dom);
25975 this.currentTip.enter();
25978 leave : function(ev)
25980 var dom = ev.getTarget();
25981 //Roo.log(['leave',dom]);
25982 if (!this.currentEl) {
25987 if (dom != this.currentEl.dom) {
25990 var xy = ev.getXY();
25991 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25994 // only activate leave if mouse cursor is outside... bounding box..
25999 if (this.currentTip) {
26000 this.currentTip.leave();
26002 //Roo.log('clear currentEl');
26003 this.currentEl = false;
26008 'left' : ['r-l', [-2,0], 'right'],
26009 'right' : ['l-r', [2,0], 'left'],
26010 'bottom' : ['t-b', [0,2], 'top'],
26011 'top' : [ 'b-t', [0,-2], 'bottom']
26017 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26022 delay : null, // can be { show : 300 , hide: 500}
26026 hoverState : null, //???
26028 placement : 'bottom',
26032 getAutoCreate : function(){
26039 cls : 'tooltip-arrow'
26042 cls : 'tooltip-inner'
26049 bind : function(el)
26055 enter : function () {
26057 if (this.timeout != null) {
26058 clearTimeout(this.timeout);
26061 this.hoverState = 'in';
26062 //Roo.log("enter - show");
26063 if (!this.delay || !this.delay.show) {
26068 this.timeout = setTimeout(function () {
26069 if (_t.hoverState == 'in') {
26072 }, this.delay.show);
26076 clearTimeout(this.timeout);
26078 this.hoverState = 'out';
26079 if (!this.delay || !this.delay.hide) {
26085 this.timeout = setTimeout(function () {
26086 //Roo.log("leave - timeout");
26088 if (_t.hoverState == 'out') {
26090 Roo.bootstrap.Tooltip.currentEl = false;
26095 show : function (msg)
26098 this.render(document.body);
26101 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26103 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26105 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26107 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26109 var placement = typeof this.placement == 'function' ?
26110 this.placement.call(this, this.el, on_el) :
26113 var autoToken = /\s?auto?\s?/i;
26114 var autoPlace = autoToken.test(placement);
26116 placement = placement.replace(autoToken, '') || 'top';
26120 //this.el.setXY([0,0]);
26122 //this.el.dom.style.display='block';
26124 //this.el.appendTo(on_el);
26126 var p = this.getPosition();
26127 var box = this.el.getBox();
26133 var align = this.alignment[placement];
26135 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26137 if(placement == 'top' || placement == 'bottom'){
26139 placement = 'right';
26142 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26143 placement = 'left';
26146 var scroll = Roo.select('body', true).first().getScroll();
26148 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26154 this.el.alignTo(this.bindEl, align[0],align[1]);
26155 //var arrow = this.el.select('.arrow',true).first();
26156 //arrow.set(align[2],
26158 this.el.addClass(placement);
26160 this.el.addClass('in fade');
26162 this.hoverState = null;
26164 if (this.el.hasClass('fade')) {
26175 //this.el.setXY([0,0]);
26176 this.el.removeClass('in');
26192 * @class Roo.bootstrap.LocationPicker
26193 * @extends Roo.bootstrap.Component
26194 * Bootstrap LocationPicker class
26195 * @cfg {Number} latitude Position when init default 0
26196 * @cfg {Number} longitude Position when init default 0
26197 * @cfg {Number} zoom default 15
26198 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26199 * @cfg {Boolean} mapTypeControl default false
26200 * @cfg {Boolean} disableDoubleClickZoom default false
26201 * @cfg {Boolean} scrollwheel default true
26202 * @cfg {Boolean} streetViewControl default false
26203 * @cfg {Number} radius default 0
26204 * @cfg {String} locationName
26205 * @cfg {Boolean} draggable default true
26206 * @cfg {Boolean} enableAutocomplete default false
26207 * @cfg {Boolean} enableReverseGeocode default true
26208 * @cfg {String} markerTitle
26211 * Create a new LocationPicker
26212 * @param {Object} config The config object
26216 Roo.bootstrap.LocationPicker = function(config){
26218 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26223 * Fires when the picker initialized.
26224 * @param {Roo.bootstrap.LocationPicker} this
26225 * @param {Google Location} location
26229 * @event positionchanged
26230 * Fires when the picker position changed.
26231 * @param {Roo.bootstrap.LocationPicker} this
26232 * @param {Google Location} location
26234 positionchanged : true,
26237 * Fires when the map resize.
26238 * @param {Roo.bootstrap.LocationPicker} this
26243 * Fires when the map show.
26244 * @param {Roo.bootstrap.LocationPicker} this
26249 * Fires when the map hide.
26250 * @param {Roo.bootstrap.LocationPicker} this
26255 * Fires when click the map.
26256 * @param {Roo.bootstrap.LocationPicker} this
26257 * @param {Map event} e
26261 * @event mapRightClick
26262 * Fires when right click the map.
26263 * @param {Roo.bootstrap.LocationPicker} this
26264 * @param {Map event} e
26266 mapRightClick : true,
26268 * @event markerClick
26269 * Fires when click the marker.
26270 * @param {Roo.bootstrap.LocationPicker} this
26271 * @param {Map event} e
26273 markerClick : true,
26275 * @event markerRightClick
26276 * Fires when right click the marker.
26277 * @param {Roo.bootstrap.LocationPicker} this
26278 * @param {Map event} e
26280 markerRightClick : true,
26282 * @event OverlayViewDraw
26283 * Fires when OverlayView Draw
26284 * @param {Roo.bootstrap.LocationPicker} this
26286 OverlayViewDraw : true,
26288 * @event OverlayViewOnAdd
26289 * Fires when OverlayView Draw
26290 * @param {Roo.bootstrap.LocationPicker} this
26292 OverlayViewOnAdd : true,
26294 * @event OverlayViewOnRemove
26295 * Fires when OverlayView Draw
26296 * @param {Roo.bootstrap.LocationPicker} this
26298 OverlayViewOnRemove : true,
26300 * @event OverlayViewShow
26301 * Fires when OverlayView Draw
26302 * @param {Roo.bootstrap.LocationPicker} this
26303 * @param {Pixel} cpx
26305 OverlayViewShow : true,
26307 * @event OverlayViewHide
26308 * Fires when OverlayView Draw
26309 * @param {Roo.bootstrap.LocationPicker} this
26311 OverlayViewHide : true,
26313 * @event loadexception
26314 * Fires when load google lib failed.
26315 * @param {Roo.bootstrap.LocationPicker} this
26317 loadexception : true
26322 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26324 gMapContext: false,
26330 mapTypeControl: false,
26331 disableDoubleClickZoom: false,
26333 streetViewControl: false,
26337 enableAutocomplete: false,
26338 enableReverseGeocode: true,
26341 getAutoCreate: function()
26346 cls: 'roo-location-picker'
26352 initEvents: function(ct, position)
26354 if(!this.el.getWidth() || this.isApplied()){
26358 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26363 initial: function()
26365 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26366 this.fireEvent('loadexception', this);
26370 if(!this.mapTypeId){
26371 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26374 this.gMapContext = this.GMapContext();
26376 this.initOverlayView();
26378 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26382 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26383 _this.setPosition(_this.gMapContext.marker.position);
26386 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26387 _this.fireEvent('mapClick', this, event);
26391 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26392 _this.fireEvent('mapRightClick', this, event);
26396 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26397 _this.fireEvent('markerClick', this, event);
26401 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26402 _this.fireEvent('markerRightClick', this, event);
26406 this.setPosition(this.gMapContext.location);
26408 this.fireEvent('initial', this, this.gMapContext.location);
26411 initOverlayView: function()
26415 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26419 _this.fireEvent('OverlayViewDraw', _this);
26424 _this.fireEvent('OverlayViewOnAdd', _this);
26427 onRemove: function()
26429 _this.fireEvent('OverlayViewOnRemove', _this);
26432 show: function(cpx)
26434 _this.fireEvent('OverlayViewShow', _this, cpx);
26439 _this.fireEvent('OverlayViewHide', _this);
26445 fromLatLngToContainerPixel: function(event)
26447 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26450 isApplied: function()
26452 return this.getGmapContext() == false ? false : true;
26455 getGmapContext: function()
26457 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26460 GMapContext: function()
26462 var position = new google.maps.LatLng(this.latitude, this.longitude);
26464 var _map = new google.maps.Map(this.el.dom, {
26467 mapTypeId: this.mapTypeId,
26468 mapTypeControl: this.mapTypeControl,
26469 disableDoubleClickZoom: this.disableDoubleClickZoom,
26470 scrollwheel: this.scrollwheel,
26471 streetViewControl: this.streetViewControl,
26472 locationName: this.locationName,
26473 draggable: this.draggable,
26474 enableAutocomplete: this.enableAutocomplete,
26475 enableReverseGeocode: this.enableReverseGeocode
26478 var _marker = new google.maps.Marker({
26479 position: position,
26481 title: this.markerTitle,
26482 draggable: this.draggable
26489 location: position,
26490 radius: this.radius,
26491 locationName: this.locationName,
26492 addressComponents: {
26493 formatted_address: null,
26494 addressLine1: null,
26495 addressLine2: null,
26497 streetNumber: null,
26501 stateOrProvince: null
26504 domContainer: this.el.dom,
26505 geodecoder: new google.maps.Geocoder()
26509 drawCircle: function(center, radius, options)
26511 if (this.gMapContext.circle != null) {
26512 this.gMapContext.circle.setMap(null);
26516 options = Roo.apply({}, options, {
26517 strokeColor: "#0000FF",
26518 strokeOpacity: .35,
26520 fillColor: "#0000FF",
26524 options.map = this.gMapContext.map;
26525 options.radius = radius;
26526 options.center = center;
26527 this.gMapContext.circle = new google.maps.Circle(options);
26528 return this.gMapContext.circle;
26534 setPosition: function(location)
26536 this.gMapContext.location = location;
26537 this.gMapContext.marker.setPosition(location);
26538 this.gMapContext.map.panTo(location);
26539 this.drawCircle(location, this.gMapContext.radius, {});
26543 if (this.gMapContext.settings.enableReverseGeocode) {
26544 this.gMapContext.geodecoder.geocode({
26545 latLng: this.gMapContext.location
26546 }, function(results, status) {
26548 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26549 _this.gMapContext.locationName = results[0].formatted_address;
26550 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26552 _this.fireEvent('positionchanged', this, location);
26559 this.fireEvent('positionchanged', this, location);
26564 google.maps.event.trigger(this.gMapContext.map, "resize");
26566 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26568 this.fireEvent('resize', this);
26571 setPositionByLatLng: function(latitude, longitude)
26573 this.setPosition(new google.maps.LatLng(latitude, longitude));
26576 getCurrentPosition: function()
26579 latitude: this.gMapContext.location.lat(),
26580 longitude: this.gMapContext.location.lng()
26584 getAddressName: function()
26586 return this.gMapContext.locationName;
26589 getAddressComponents: function()
26591 return this.gMapContext.addressComponents;
26594 address_component_from_google_geocode: function(address_components)
26598 for (var i = 0; i < address_components.length; i++) {
26599 var component = address_components[i];
26600 if (component.types.indexOf("postal_code") >= 0) {
26601 result.postalCode = component.short_name;
26602 } else if (component.types.indexOf("street_number") >= 0) {
26603 result.streetNumber = component.short_name;
26604 } else if (component.types.indexOf("route") >= 0) {
26605 result.streetName = component.short_name;
26606 } else if (component.types.indexOf("neighborhood") >= 0) {
26607 result.city = component.short_name;
26608 } else if (component.types.indexOf("locality") >= 0) {
26609 result.city = component.short_name;
26610 } else if (component.types.indexOf("sublocality") >= 0) {
26611 result.district = component.short_name;
26612 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26613 result.stateOrProvince = component.short_name;
26614 } else if (component.types.indexOf("country") >= 0) {
26615 result.country = component.short_name;
26619 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26620 result.addressLine2 = "";
26624 setZoomLevel: function(zoom)
26626 this.gMapContext.map.setZoom(zoom);
26639 this.fireEvent('show', this);
26650 this.fireEvent('hide', this);
26655 Roo.apply(Roo.bootstrap.LocationPicker, {
26657 OverlayView : function(map, options)
26659 options = options || {};
26673 * @class Roo.bootstrap.Alert
26674 * @extends Roo.bootstrap.Component
26675 * Bootstrap Alert class
26676 * @cfg {String} title The title of alert
26677 * @cfg {String} html The content of alert
26678 * @cfg {String} weight ( success | info | warning | danger )
26679 * @cfg {String} faicon font-awesomeicon
26682 * Create a new alert
26683 * @param {Object} config The config object
26687 Roo.bootstrap.Alert = function(config){
26688 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26692 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26699 getAutoCreate : function()
26708 cls : 'roo-alert-icon'
26713 cls : 'roo-alert-title',
26718 cls : 'roo-alert-text',
26725 cfg.cn[0].cls += ' fa ' + this.faicon;
26729 cfg.cls += ' alert-' + this.weight;
26735 initEvents: function()
26737 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26740 setTitle : function(str)
26742 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26745 setText : function(str)
26747 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26750 setWeight : function(weight)
26753 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26756 this.weight = weight;
26758 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26761 setIcon : function(icon)
26764 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26767 this.faicon = icon;
26769 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26790 * @class Roo.bootstrap.UploadCropbox
26791 * @extends Roo.bootstrap.Component
26792 * Bootstrap UploadCropbox class
26793 * @cfg {String} emptyText show when image has been loaded
26794 * @cfg {String} rotateNotify show when image too small to rotate
26795 * @cfg {Number} errorTimeout default 3000
26796 * @cfg {Number} minWidth default 300
26797 * @cfg {Number} minHeight default 300
26798 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26799 * @cfg {Boolean} isDocument (true|false) default false
26800 * @cfg {String} url action url
26801 * @cfg {String} paramName default 'imageUpload'
26802 * @cfg {String} method default POST
26803 * @cfg {Boolean} loadMask (true|false) default true
26804 * @cfg {Boolean} loadingText default 'Loading...'
26807 * Create a new UploadCropbox
26808 * @param {Object} config The config object
26811 Roo.bootstrap.UploadCropbox = function(config){
26812 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26816 * @event beforeselectfile
26817 * Fire before select file
26818 * @param {Roo.bootstrap.UploadCropbox} this
26820 "beforeselectfile" : true,
26823 * Fire after initEvent
26824 * @param {Roo.bootstrap.UploadCropbox} this
26829 * Fire after initEvent
26830 * @param {Roo.bootstrap.UploadCropbox} this
26831 * @param {String} data
26836 * Fire when preparing the file data
26837 * @param {Roo.bootstrap.UploadCropbox} this
26838 * @param {Object} file
26843 * Fire when get exception
26844 * @param {Roo.bootstrap.UploadCropbox} this
26845 * @param {XMLHttpRequest} xhr
26847 "exception" : true,
26849 * @event beforeloadcanvas
26850 * Fire before load the canvas
26851 * @param {Roo.bootstrap.UploadCropbox} this
26852 * @param {String} src
26854 "beforeloadcanvas" : true,
26857 * Fire when trash image
26858 * @param {Roo.bootstrap.UploadCropbox} this
26863 * Fire when download the image
26864 * @param {Roo.bootstrap.UploadCropbox} this
26868 * @event footerbuttonclick
26869 * Fire when footerbuttonclick
26870 * @param {Roo.bootstrap.UploadCropbox} this
26871 * @param {String} type
26873 "footerbuttonclick" : true,
26877 * @param {Roo.bootstrap.UploadCropbox} this
26882 * Fire when rotate the image
26883 * @param {Roo.bootstrap.UploadCropbox} this
26884 * @param {String} pos
26889 * Fire when inspect the file
26890 * @param {Roo.bootstrap.UploadCropbox} this
26891 * @param {Object} file
26896 * Fire when xhr upload the file
26897 * @param {Roo.bootstrap.UploadCropbox} this
26898 * @param {Object} data
26903 * Fire when arrange the file data
26904 * @param {Roo.bootstrap.UploadCropbox} this
26905 * @param {Object} formData
26910 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26913 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26915 emptyText : 'Click to upload image',
26916 rotateNotify : 'Image is too small to rotate',
26917 errorTimeout : 3000,
26931 cropType : 'image/jpeg',
26933 canvasLoaded : false,
26934 isDocument : false,
26936 paramName : 'imageUpload',
26938 loadingText : 'Loading...',
26941 getAutoCreate : function()
26945 cls : 'roo-upload-cropbox',
26949 cls : 'roo-upload-cropbox-selector',
26954 cls : 'roo-upload-cropbox-body',
26955 style : 'cursor:pointer',
26959 cls : 'roo-upload-cropbox-preview'
26963 cls : 'roo-upload-cropbox-thumb'
26967 cls : 'roo-upload-cropbox-empty-notify',
26968 html : this.emptyText
26972 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26973 html : this.rotateNotify
26979 cls : 'roo-upload-cropbox-footer',
26982 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26992 onRender : function(ct, position)
26994 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26996 if (this.buttons.length) {
26998 Roo.each(this.buttons, function(bb) {
27000 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27002 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27008 this.maskEl = this.el;
27012 initEvents : function()
27014 this.urlAPI = (window.createObjectURL && window) ||
27015 (window.URL && URL.revokeObjectURL && URL) ||
27016 (window.webkitURL && webkitURL);
27018 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27019 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27021 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27022 this.selectorEl.hide();
27024 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27025 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27027 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27028 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27029 this.thumbEl.hide();
27031 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27032 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27034 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27035 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27036 this.errorEl.hide();
27038 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27039 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27040 this.footerEl.hide();
27042 this.setThumbBoxSize();
27048 this.fireEvent('initial', this);
27055 window.addEventListener("resize", function() { _this.resize(); } );
27057 this.bodyEl.on('click', this.beforeSelectFile, this);
27060 this.bodyEl.on('touchstart', this.onTouchStart, this);
27061 this.bodyEl.on('touchmove', this.onTouchMove, this);
27062 this.bodyEl.on('touchend', this.onTouchEnd, this);
27066 this.bodyEl.on('mousedown', this.onMouseDown, this);
27067 this.bodyEl.on('mousemove', this.onMouseMove, this);
27068 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27069 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27070 Roo.get(document).on('mouseup', this.onMouseUp, this);
27073 this.selectorEl.on('change', this.onFileSelected, this);
27079 this.baseScale = 1;
27081 this.baseRotate = 1;
27082 this.dragable = false;
27083 this.pinching = false;
27086 this.cropData = false;
27087 this.notifyEl.dom.innerHTML = this.emptyText;
27089 this.selectorEl.dom.value = '';
27093 resize : function()
27095 if(this.fireEvent('resize', this) != false){
27096 this.setThumbBoxPosition();
27097 this.setCanvasPosition();
27101 onFooterButtonClick : function(e, el, o, type)
27104 case 'rotate-left' :
27105 this.onRotateLeft(e);
27107 case 'rotate-right' :
27108 this.onRotateRight(e);
27111 this.beforeSelectFile(e);
27126 this.fireEvent('footerbuttonclick', this, type);
27129 beforeSelectFile : function(e)
27131 e.preventDefault();
27133 if(this.fireEvent('beforeselectfile', this) != false){
27134 this.selectorEl.dom.click();
27138 onFileSelected : function(e)
27140 e.preventDefault();
27142 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27146 var file = this.selectorEl.dom.files[0];
27148 if(this.fireEvent('inspect', this, file) != false){
27149 this.prepare(file);
27154 trash : function(e)
27156 this.fireEvent('trash', this);
27159 download : function(e)
27161 this.fireEvent('download', this);
27164 loadCanvas : function(src)
27166 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27170 this.imageEl = document.createElement('img');
27174 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27176 this.imageEl.src = src;
27180 onLoadCanvas : function()
27182 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27183 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27185 this.bodyEl.un('click', this.beforeSelectFile, this);
27187 this.notifyEl.hide();
27188 this.thumbEl.show();
27189 this.footerEl.show();
27191 this.baseRotateLevel();
27193 if(this.isDocument){
27194 this.setThumbBoxSize();
27197 this.setThumbBoxPosition();
27199 this.baseScaleLevel();
27205 this.canvasLoaded = true;
27208 this.maskEl.unmask();
27213 setCanvasPosition : function()
27215 if(!this.canvasEl){
27219 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27220 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27222 this.previewEl.setLeft(pw);
27223 this.previewEl.setTop(ph);
27227 onMouseDown : function(e)
27231 this.dragable = true;
27232 this.pinching = false;
27234 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27235 this.dragable = false;
27239 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27240 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27244 onMouseMove : function(e)
27248 if(!this.canvasLoaded){
27252 if (!this.dragable){
27256 var minX = Math.ceil(this.thumbEl.getLeft(true));
27257 var minY = Math.ceil(this.thumbEl.getTop(true));
27259 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27260 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27262 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27263 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27265 x = x - this.mouseX;
27266 y = y - this.mouseY;
27268 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27269 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27271 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27272 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27274 this.previewEl.setLeft(bgX);
27275 this.previewEl.setTop(bgY);
27277 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27278 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27281 onMouseUp : function(e)
27285 this.dragable = false;
27288 onMouseWheel : function(e)
27292 this.startScale = this.scale;
27294 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27296 if(!this.zoomable()){
27297 this.scale = this.startScale;
27306 zoomable : function()
27308 var minScale = this.thumbEl.getWidth() / this.minWidth;
27310 if(this.minWidth < this.minHeight){
27311 minScale = this.thumbEl.getHeight() / this.minHeight;
27314 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27315 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27319 (this.rotate == 0 || this.rotate == 180) &&
27321 width > this.imageEl.OriginWidth ||
27322 height > this.imageEl.OriginHeight ||
27323 (width < this.minWidth && height < this.minHeight)
27331 (this.rotate == 90 || this.rotate == 270) &&
27333 width > this.imageEl.OriginWidth ||
27334 height > this.imageEl.OriginHeight ||
27335 (width < this.minHeight && height < this.minWidth)
27342 !this.isDocument &&
27343 (this.rotate == 0 || this.rotate == 180) &&
27345 width < this.minWidth ||
27346 width > this.imageEl.OriginWidth ||
27347 height < this.minHeight ||
27348 height > this.imageEl.OriginHeight
27355 !this.isDocument &&
27356 (this.rotate == 90 || this.rotate == 270) &&
27358 width < this.minHeight ||
27359 width > this.imageEl.OriginWidth ||
27360 height < this.minWidth ||
27361 height > this.imageEl.OriginHeight
27371 onRotateLeft : function(e)
27373 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27375 var minScale = this.thumbEl.getWidth() / this.minWidth;
27377 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27378 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27380 this.startScale = this.scale;
27382 while (this.getScaleLevel() < minScale){
27384 this.scale = this.scale + 1;
27386 if(!this.zoomable()){
27391 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27392 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27397 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27404 this.scale = this.startScale;
27406 this.onRotateFail();
27411 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27413 if(this.isDocument){
27414 this.setThumbBoxSize();
27415 this.setThumbBoxPosition();
27416 this.setCanvasPosition();
27421 this.fireEvent('rotate', this, 'left');
27425 onRotateRight : function(e)
27427 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27429 var minScale = this.thumbEl.getWidth() / this.minWidth;
27431 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27432 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27434 this.startScale = this.scale;
27436 while (this.getScaleLevel() < minScale){
27438 this.scale = this.scale + 1;
27440 if(!this.zoomable()){
27445 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27446 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27451 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27458 this.scale = this.startScale;
27460 this.onRotateFail();
27465 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27467 if(this.isDocument){
27468 this.setThumbBoxSize();
27469 this.setThumbBoxPosition();
27470 this.setCanvasPosition();
27475 this.fireEvent('rotate', this, 'right');
27478 onRotateFail : function()
27480 this.errorEl.show(true);
27484 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27489 this.previewEl.dom.innerHTML = '';
27491 var canvasEl = document.createElement("canvas");
27493 var contextEl = canvasEl.getContext("2d");
27495 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27496 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27497 var center = this.imageEl.OriginWidth / 2;
27499 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27500 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27501 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27502 center = this.imageEl.OriginHeight / 2;
27505 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27507 contextEl.translate(center, center);
27508 contextEl.rotate(this.rotate * Math.PI / 180);
27510 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27512 this.canvasEl = document.createElement("canvas");
27514 this.contextEl = this.canvasEl.getContext("2d");
27516 switch (this.rotate) {
27519 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27520 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27522 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27527 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27528 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27530 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27531 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);
27535 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27540 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27541 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27543 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27544 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);
27548 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);
27553 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27554 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27556 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27557 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27561 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);
27568 this.previewEl.appendChild(this.canvasEl);
27570 this.setCanvasPosition();
27575 if(!this.canvasLoaded){
27579 var imageCanvas = document.createElement("canvas");
27581 var imageContext = imageCanvas.getContext("2d");
27583 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27584 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27586 var center = imageCanvas.width / 2;
27588 imageContext.translate(center, center);
27590 imageContext.rotate(this.rotate * Math.PI / 180);
27592 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27594 var canvas = document.createElement("canvas");
27596 var context = canvas.getContext("2d");
27598 canvas.width = this.minWidth;
27599 canvas.height = this.minHeight;
27601 switch (this.rotate) {
27604 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27605 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27607 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27608 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27610 var targetWidth = this.minWidth - 2 * x;
27611 var targetHeight = this.minHeight - 2 * y;
27615 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27616 scale = targetWidth / width;
27619 if(x > 0 && y == 0){
27620 scale = targetHeight / height;
27623 if(x > 0 && y > 0){
27624 scale = targetWidth / width;
27626 if(width < height){
27627 scale = targetHeight / height;
27631 context.scale(scale, scale);
27633 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27634 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27636 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27637 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27639 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27644 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27645 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27647 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27648 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27650 var targetWidth = this.minWidth - 2 * x;
27651 var targetHeight = this.minHeight - 2 * y;
27655 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27656 scale = targetWidth / width;
27659 if(x > 0 && y == 0){
27660 scale = targetHeight / height;
27663 if(x > 0 && y > 0){
27664 scale = targetWidth / width;
27666 if(width < height){
27667 scale = targetHeight / height;
27671 context.scale(scale, scale);
27673 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27674 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27676 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27677 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27679 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27681 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27686 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27687 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27689 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27690 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27692 var targetWidth = this.minWidth - 2 * x;
27693 var targetHeight = this.minHeight - 2 * y;
27697 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27698 scale = targetWidth / width;
27701 if(x > 0 && y == 0){
27702 scale = targetHeight / height;
27705 if(x > 0 && y > 0){
27706 scale = targetWidth / width;
27708 if(width < height){
27709 scale = targetHeight / height;
27713 context.scale(scale, scale);
27715 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27716 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27718 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27719 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27721 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27722 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27724 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27729 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27730 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27732 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27733 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27735 var targetWidth = this.minWidth - 2 * x;
27736 var targetHeight = this.minHeight - 2 * y;
27740 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27741 scale = targetWidth / width;
27744 if(x > 0 && y == 0){
27745 scale = targetHeight / height;
27748 if(x > 0 && y > 0){
27749 scale = targetWidth / width;
27751 if(width < height){
27752 scale = targetHeight / height;
27756 context.scale(scale, scale);
27758 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27759 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27761 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27762 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27764 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27766 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27773 this.cropData = canvas.toDataURL(this.cropType);
27775 if(this.fireEvent('crop', this, this.cropData) !== false){
27776 this.process(this.file, this.cropData);
27783 setThumbBoxSize : function()
27787 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27788 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27789 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27791 this.minWidth = width;
27792 this.minHeight = height;
27794 if(this.rotate == 90 || this.rotate == 270){
27795 this.minWidth = height;
27796 this.minHeight = width;
27801 width = Math.ceil(this.minWidth * height / this.minHeight);
27803 if(this.minWidth > this.minHeight){
27805 height = Math.ceil(this.minHeight * width / this.minWidth);
27808 this.thumbEl.setStyle({
27809 width : width + 'px',
27810 height : height + 'px'
27817 setThumbBoxPosition : function()
27819 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27820 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27822 this.thumbEl.setLeft(x);
27823 this.thumbEl.setTop(y);
27827 baseRotateLevel : function()
27829 this.baseRotate = 1;
27832 typeof(this.exif) != 'undefined' &&
27833 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27834 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27836 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27839 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27843 baseScaleLevel : function()
27847 if(this.isDocument){
27849 if(this.baseRotate == 6 || this.baseRotate == 8){
27851 height = this.thumbEl.getHeight();
27852 this.baseScale = height / this.imageEl.OriginWidth;
27854 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27855 width = this.thumbEl.getWidth();
27856 this.baseScale = width / this.imageEl.OriginHeight;
27862 height = this.thumbEl.getHeight();
27863 this.baseScale = height / this.imageEl.OriginHeight;
27865 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27866 width = this.thumbEl.getWidth();
27867 this.baseScale = width / this.imageEl.OriginWidth;
27873 if(this.baseRotate == 6 || this.baseRotate == 8){
27875 width = this.thumbEl.getHeight();
27876 this.baseScale = width / this.imageEl.OriginHeight;
27878 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27879 height = this.thumbEl.getWidth();
27880 this.baseScale = height / this.imageEl.OriginHeight;
27883 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27884 height = this.thumbEl.getWidth();
27885 this.baseScale = height / this.imageEl.OriginHeight;
27887 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27888 width = this.thumbEl.getHeight();
27889 this.baseScale = width / this.imageEl.OriginWidth;
27896 width = this.thumbEl.getWidth();
27897 this.baseScale = width / this.imageEl.OriginWidth;
27899 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27900 height = this.thumbEl.getHeight();
27901 this.baseScale = height / this.imageEl.OriginHeight;
27904 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27906 height = this.thumbEl.getHeight();
27907 this.baseScale = height / this.imageEl.OriginHeight;
27909 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27910 width = this.thumbEl.getWidth();
27911 this.baseScale = width / this.imageEl.OriginWidth;
27919 getScaleLevel : function()
27921 return this.baseScale * Math.pow(1.1, this.scale);
27924 onTouchStart : function(e)
27926 if(!this.canvasLoaded){
27927 this.beforeSelectFile(e);
27931 var touches = e.browserEvent.touches;
27937 if(touches.length == 1){
27938 this.onMouseDown(e);
27942 if(touches.length != 2){
27948 for(var i = 0, finger; finger = touches[i]; i++){
27949 coords.push(finger.pageX, finger.pageY);
27952 var x = Math.pow(coords[0] - coords[2], 2);
27953 var y = Math.pow(coords[1] - coords[3], 2);
27955 this.startDistance = Math.sqrt(x + y);
27957 this.startScale = this.scale;
27959 this.pinching = true;
27960 this.dragable = false;
27964 onTouchMove : function(e)
27966 if(!this.pinching && !this.dragable){
27970 var touches = e.browserEvent.touches;
27977 this.onMouseMove(e);
27983 for(var i = 0, finger; finger = touches[i]; i++){
27984 coords.push(finger.pageX, finger.pageY);
27987 var x = Math.pow(coords[0] - coords[2], 2);
27988 var y = Math.pow(coords[1] - coords[3], 2);
27990 this.endDistance = Math.sqrt(x + y);
27992 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27994 if(!this.zoomable()){
27995 this.scale = this.startScale;
28003 onTouchEnd : function(e)
28005 this.pinching = false;
28006 this.dragable = false;
28010 process : function(file, crop)
28013 this.maskEl.mask(this.loadingText);
28016 this.xhr = new XMLHttpRequest();
28018 file.xhr = this.xhr;
28020 this.xhr.open(this.method, this.url, true);
28023 "Accept": "application/json",
28024 "Cache-Control": "no-cache",
28025 "X-Requested-With": "XMLHttpRequest"
28028 for (var headerName in headers) {
28029 var headerValue = headers[headerName];
28031 this.xhr.setRequestHeader(headerName, headerValue);
28037 this.xhr.onload = function()
28039 _this.xhrOnLoad(_this.xhr);
28042 this.xhr.onerror = function()
28044 _this.xhrOnError(_this.xhr);
28047 var formData = new FormData();
28049 formData.append('returnHTML', 'NO');
28052 formData.append('crop', crop);
28055 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28056 formData.append(this.paramName, file, file.name);
28059 if(typeof(file.filename) != 'undefined'){
28060 formData.append('filename', file.filename);
28063 if(typeof(file.mimetype) != 'undefined'){
28064 formData.append('mimetype', file.mimetype);
28067 if(this.fireEvent('arrange', this, formData) != false){
28068 this.xhr.send(formData);
28072 xhrOnLoad : function(xhr)
28075 this.maskEl.unmask();
28078 if (xhr.readyState !== 4) {
28079 this.fireEvent('exception', this, xhr);
28083 var response = Roo.decode(xhr.responseText);
28085 if(!response.success){
28086 this.fireEvent('exception', this, xhr);
28090 var response = Roo.decode(xhr.responseText);
28092 this.fireEvent('upload', this, response);
28096 xhrOnError : function()
28099 this.maskEl.unmask();
28102 Roo.log('xhr on error');
28104 var response = Roo.decode(xhr.responseText);
28110 prepare : function(file)
28113 this.maskEl.mask(this.loadingText);
28119 if(typeof(file) === 'string'){
28120 this.loadCanvas(file);
28124 if(!file || !this.urlAPI){
28129 this.cropType = file.type;
28133 if(this.fireEvent('prepare', this, this.file) != false){
28135 var reader = new FileReader();
28137 reader.onload = function (e) {
28138 if (e.target.error) {
28139 Roo.log(e.target.error);
28143 var buffer = e.target.result,
28144 dataView = new DataView(buffer),
28146 maxOffset = dataView.byteLength - 4,
28150 if (dataView.getUint16(0) === 0xffd8) {
28151 while (offset < maxOffset) {
28152 markerBytes = dataView.getUint16(offset);
28154 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28155 markerLength = dataView.getUint16(offset + 2) + 2;
28156 if (offset + markerLength > dataView.byteLength) {
28157 Roo.log('Invalid meta data: Invalid segment size.');
28161 if(markerBytes == 0xffe1){
28162 _this.parseExifData(
28169 offset += markerLength;
28179 var url = _this.urlAPI.createObjectURL(_this.file);
28181 _this.loadCanvas(url);
28186 reader.readAsArrayBuffer(this.file);
28192 parseExifData : function(dataView, offset, length)
28194 var tiffOffset = offset + 10,
28198 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28199 // No Exif data, might be XMP data instead
28203 // Check for the ASCII code for "Exif" (0x45786966):
28204 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28205 // No Exif data, might be XMP data instead
28208 if (tiffOffset + 8 > dataView.byteLength) {
28209 Roo.log('Invalid Exif data: Invalid segment size.');
28212 // Check for the two null bytes:
28213 if (dataView.getUint16(offset + 8) !== 0x0000) {
28214 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28217 // Check the byte alignment:
28218 switch (dataView.getUint16(tiffOffset)) {
28220 littleEndian = true;
28223 littleEndian = false;
28226 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28229 // Check for the TIFF tag marker (0x002A):
28230 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28231 Roo.log('Invalid Exif data: Missing TIFF marker.');
28234 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28235 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28237 this.parseExifTags(
28240 tiffOffset + dirOffset,
28245 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28250 if (dirOffset + 6 > dataView.byteLength) {
28251 Roo.log('Invalid Exif data: Invalid directory offset.');
28254 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28255 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28256 if (dirEndOffset + 4 > dataView.byteLength) {
28257 Roo.log('Invalid Exif data: Invalid directory size.');
28260 for (i = 0; i < tagsNumber; i += 1) {
28264 dirOffset + 2 + 12 * i, // tag offset
28268 // Return the offset to the next directory:
28269 return dataView.getUint32(dirEndOffset, littleEndian);
28272 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28274 var tag = dataView.getUint16(offset, littleEndian);
28276 this.exif[tag] = this.getExifValue(
28280 dataView.getUint16(offset + 2, littleEndian), // tag type
28281 dataView.getUint32(offset + 4, littleEndian), // tag length
28286 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28288 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28297 Roo.log('Invalid Exif data: Invalid tag type.');
28301 tagSize = tagType.size * length;
28302 // Determine if the value is contained in the dataOffset bytes,
28303 // or if the value at the dataOffset is a pointer to the actual data:
28304 dataOffset = tagSize > 4 ?
28305 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28306 if (dataOffset + tagSize > dataView.byteLength) {
28307 Roo.log('Invalid Exif data: Invalid data offset.');
28310 if (length === 1) {
28311 return tagType.getValue(dataView, dataOffset, littleEndian);
28314 for (i = 0; i < length; i += 1) {
28315 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28318 if (tagType.ascii) {
28320 // Concatenate the chars:
28321 for (i = 0; i < values.length; i += 1) {
28323 // Ignore the terminating NULL byte(s):
28324 if (c === '\u0000') {
28336 Roo.apply(Roo.bootstrap.UploadCropbox, {
28338 'Orientation': 0x0112
28342 1: 0, //'top-left',
28344 3: 180, //'bottom-right',
28345 // 4: 'bottom-left',
28347 6: 90, //'right-top',
28348 // 7: 'right-bottom',
28349 8: 270 //'left-bottom'
28353 // byte, 8-bit unsigned int:
28355 getValue: function (dataView, dataOffset) {
28356 return dataView.getUint8(dataOffset);
28360 // ascii, 8-bit byte:
28362 getValue: function (dataView, dataOffset) {
28363 return String.fromCharCode(dataView.getUint8(dataOffset));
28368 // short, 16 bit int:
28370 getValue: function (dataView, dataOffset, littleEndian) {
28371 return dataView.getUint16(dataOffset, littleEndian);
28375 // long, 32 bit int:
28377 getValue: function (dataView, dataOffset, littleEndian) {
28378 return dataView.getUint32(dataOffset, littleEndian);
28382 // rational = two long values, first is numerator, second is denominator:
28384 getValue: function (dataView, dataOffset, littleEndian) {
28385 return dataView.getUint32(dataOffset, littleEndian) /
28386 dataView.getUint32(dataOffset + 4, littleEndian);
28390 // slong, 32 bit signed int:
28392 getValue: function (dataView, dataOffset, littleEndian) {
28393 return dataView.getInt32(dataOffset, littleEndian);
28397 // srational, two slongs, first is numerator, second is denominator:
28399 getValue: function (dataView, dataOffset, littleEndian) {
28400 return dataView.getInt32(dataOffset, littleEndian) /
28401 dataView.getInt32(dataOffset + 4, littleEndian);
28411 cls : 'btn-group roo-upload-cropbox-rotate-left',
28412 action : 'rotate-left',
28416 cls : 'btn btn-default',
28417 html : '<i class="fa fa-undo"></i>'
28423 cls : 'btn-group roo-upload-cropbox-picture',
28424 action : 'picture',
28428 cls : 'btn btn-default',
28429 html : '<i class="fa fa-picture-o"></i>'
28435 cls : 'btn-group roo-upload-cropbox-rotate-right',
28436 action : 'rotate-right',
28440 cls : 'btn btn-default',
28441 html : '<i class="fa fa-repeat"></i>'
28449 cls : 'btn-group roo-upload-cropbox-rotate-left',
28450 action : 'rotate-left',
28454 cls : 'btn btn-default',
28455 html : '<i class="fa fa-undo"></i>'
28461 cls : 'btn-group roo-upload-cropbox-download',
28462 action : 'download',
28466 cls : 'btn btn-default',
28467 html : '<i class="fa fa-download"></i>'
28473 cls : 'btn-group roo-upload-cropbox-crop',
28478 cls : 'btn btn-default',
28479 html : '<i class="fa fa-crop"></i>'
28485 cls : 'btn-group roo-upload-cropbox-trash',
28490 cls : 'btn btn-default',
28491 html : '<i class="fa fa-trash"></i>'
28497 cls : 'btn-group roo-upload-cropbox-rotate-right',
28498 action : 'rotate-right',
28502 cls : 'btn btn-default',
28503 html : '<i class="fa fa-repeat"></i>'
28511 cls : 'btn-group roo-upload-cropbox-rotate-left',
28512 action : 'rotate-left',
28516 cls : 'btn btn-default',
28517 html : '<i class="fa fa-undo"></i>'
28523 cls : 'btn-group roo-upload-cropbox-rotate-right',
28524 action : 'rotate-right',
28528 cls : 'btn btn-default',
28529 html : '<i class="fa fa-repeat"></i>'
28542 * @class Roo.bootstrap.DocumentManager
28543 * @extends Roo.bootstrap.Component
28544 * Bootstrap DocumentManager class
28545 * @cfg {String} paramName default 'imageUpload'
28546 * @cfg {String} toolTipName default 'filename'
28547 * @cfg {String} method default POST
28548 * @cfg {String} url action url
28549 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28550 * @cfg {Boolean} multiple multiple upload default true
28551 * @cfg {Number} thumbSize default 300
28552 * @cfg {String} fieldLabel
28553 * @cfg {Number} labelWidth default 4
28554 * @cfg {String} labelAlign (left|top) default left
28555 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28556 * @cfg {Number} labellg set the width of label (1-12)
28557 * @cfg {Number} labelmd set the width of label (1-12)
28558 * @cfg {Number} labelsm set the width of label (1-12)
28559 * @cfg {Number} labelxs set the width of label (1-12)
28562 * Create a new DocumentManager
28563 * @param {Object} config The config object
28566 Roo.bootstrap.DocumentManager = function(config){
28567 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28570 this.delegates = [];
28575 * Fire when initial the DocumentManager
28576 * @param {Roo.bootstrap.DocumentManager} this
28581 * inspect selected file
28582 * @param {Roo.bootstrap.DocumentManager} this
28583 * @param {File} file
28588 * Fire when xhr load exception
28589 * @param {Roo.bootstrap.DocumentManager} this
28590 * @param {XMLHttpRequest} xhr
28592 "exception" : true,
28594 * @event afterupload
28595 * Fire when xhr load exception
28596 * @param {Roo.bootstrap.DocumentManager} this
28597 * @param {XMLHttpRequest} xhr
28599 "afterupload" : true,
28602 * prepare the form data
28603 * @param {Roo.bootstrap.DocumentManager} this
28604 * @param {Object} formData
28609 * Fire when remove the file
28610 * @param {Roo.bootstrap.DocumentManager} this
28611 * @param {Object} file
28616 * Fire after refresh the file
28617 * @param {Roo.bootstrap.DocumentManager} this
28622 * Fire after click the image
28623 * @param {Roo.bootstrap.DocumentManager} this
28624 * @param {Object} file
28629 * Fire when upload a image and editable set to true
28630 * @param {Roo.bootstrap.DocumentManager} this
28631 * @param {Object} file
28635 * @event beforeselectfile
28636 * Fire before select file
28637 * @param {Roo.bootstrap.DocumentManager} this
28639 "beforeselectfile" : true,
28642 * Fire before process file
28643 * @param {Roo.bootstrap.DocumentManager} this
28644 * @param {Object} file
28648 * @event previewrendered
28649 * Fire when preview rendered
28650 * @param {Roo.bootstrap.DocumentManager} this
28651 * @param {Object} file
28653 "previewrendered" : true
28658 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28667 paramName : 'imageUpload',
28668 toolTipName : 'filename',
28671 labelAlign : 'left',
28681 getAutoCreate : function()
28683 var managerWidget = {
28685 cls : 'roo-document-manager',
28689 cls : 'roo-document-manager-selector',
28694 cls : 'roo-document-manager-uploader',
28698 cls : 'roo-document-manager-upload-btn',
28699 html : '<i class="fa fa-plus"></i>'
28710 cls : 'column col-md-12',
28715 if(this.fieldLabel.length){
28720 cls : 'column col-md-12',
28721 html : this.fieldLabel
28725 cls : 'column col-md-12',
28730 if(this.labelAlign == 'left'){
28735 html : this.fieldLabel
28744 if(this.labelWidth > 12){
28745 content[0].style = "width: " + this.labelWidth + 'px';
28748 if(this.labelWidth < 13 && this.labelmd == 0){
28749 this.labelmd = this.labelWidth;
28752 if(this.labellg > 0){
28753 content[0].cls += ' col-lg-' + this.labellg;
28754 content[1].cls += ' col-lg-' + (12 - this.labellg);
28757 if(this.labelmd > 0){
28758 content[0].cls += ' col-md-' + this.labelmd;
28759 content[1].cls += ' col-md-' + (12 - this.labelmd);
28762 if(this.labelsm > 0){
28763 content[0].cls += ' col-sm-' + this.labelsm;
28764 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28767 if(this.labelxs > 0){
28768 content[0].cls += ' col-xs-' + this.labelxs;
28769 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28777 cls : 'row clearfix',
28785 initEvents : function()
28787 this.managerEl = this.el.select('.roo-document-manager', true).first();
28788 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28790 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28791 this.selectorEl.hide();
28794 this.selectorEl.attr('multiple', 'multiple');
28797 this.selectorEl.on('change', this.onFileSelected, this);
28799 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28800 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28802 this.uploader.on('click', this.onUploaderClick, this);
28804 this.renderProgressDialog();
28808 window.addEventListener("resize", function() { _this.refresh(); } );
28810 this.fireEvent('initial', this);
28813 renderProgressDialog : function()
28817 this.progressDialog = new Roo.bootstrap.Modal({
28818 cls : 'roo-document-manager-progress-dialog',
28819 allow_close : false,
28829 btnclick : function() {
28830 _this.uploadCancel();
28836 this.progressDialog.render(Roo.get(document.body));
28838 this.progress = new Roo.bootstrap.Progress({
28839 cls : 'roo-document-manager-progress',
28844 this.progress.render(this.progressDialog.getChildContainer());
28846 this.progressBar = new Roo.bootstrap.ProgressBar({
28847 cls : 'roo-document-manager-progress-bar',
28850 aria_valuemax : 12,
28854 this.progressBar.render(this.progress.getChildContainer());
28857 onUploaderClick : function(e)
28859 e.preventDefault();
28861 if(this.fireEvent('beforeselectfile', this) != false){
28862 this.selectorEl.dom.click();
28867 onFileSelected : function(e)
28869 e.preventDefault();
28871 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28875 Roo.each(this.selectorEl.dom.files, function(file){
28876 if(this.fireEvent('inspect', this, file) != false){
28877 this.files.push(file);
28887 this.selectorEl.dom.value = '';
28889 if(!this.files || !this.files.length){
28893 if(this.boxes > 0 && this.files.length > this.boxes){
28894 this.files = this.files.slice(0, this.boxes);
28897 this.uploader.show();
28899 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28900 this.uploader.hide();
28909 Roo.each(this.files, function(file){
28911 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28912 var f = this.renderPreview(file);
28917 if(file.type.indexOf('image') != -1){
28918 this.delegates.push(
28920 _this.process(file);
28921 }).createDelegate(this)
28929 _this.process(file);
28930 }).createDelegate(this)
28935 this.files = files;
28937 this.delegates = this.delegates.concat(docs);
28939 if(!this.delegates.length){
28944 this.progressBar.aria_valuemax = this.delegates.length;
28951 arrange : function()
28953 if(!this.delegates.length){
28954 this.progressDialog.hide();
28959 var delegate = this.delegates.shift();
28961 this.progressDialog.show();
28963 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28965 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28970 refresh : function()
28972 this.uploader.show();
28974 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28975 this.uploader.hide();
28978 Roo.isTouch ? this.closable(false) : this.closable(true);
28980 this.fireEvent('refresh', this);
28983 onRemove : function(e, el, o)
28985 e.preventDefault();
28987 this.fireEvent('remove', this, o);
28991 remove : function(o)
28995 Roo.each(this.files, function(file){
28996 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29005 this.files = files;
29012 Roo.each(this.files, function(file){
29017 file.target.remove();
29026 onClick : function(e, el, o)
29028 e.preventDefault();
29030 this.fireEvent('click', this, o);
29034 closable : function(closable)
29036 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29038 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29050 xhrOnLoad : function(xhr)
29052 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29056 if (xhr.readyState !== 4) {
29058 this.fireEvent('exception', this, xhr);
29062 var response = Roo.decode(xhr.responseText);
29064 if(!response.success){
29066 this.fireEvent('exception', this, xhr);
29070 var file = this.renderPreview(response.data);
29072 this.files.push(file);
29076 this.fireEvent('afterupload', this, xhr);
29080 xhrOnError : function(xhr)
29082 Roo.log('xhr on error');
29084 var response = Roo.decode(xhr.responseText);
29091 process : function(file)
29093 if(this.fireEvent('process', this, file) !== false){
29094 if(this.editable && file.type.indexOf('image') != -1){
29095 this.fireEvent('edit', this, file);
29099 this.uploadStart(file, false);
29106 uploadStart : function(file, crop)
29108 this.xhr = new XMLHttpRequest();
29110 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29115 file.xhr = this.xhr;
29117 this.managerEl.createChild({
29119 cls : 'roo-document-manager-loading',
29123 tooltip : file.name,
29124 cls : 'roo-document-manager-thumb',
29125 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29131 this.xhr.open(this.method, this.url, true);
29134 "Accept": "application/json",
29135 "Cache-Control": "no-cache",
29136 "X-Requested-With": "XMLHttpRequest"
29139 for (var headerName in headers) {
29140 var headerValue = headers[headerName];
29142 this.xhr.setRequestHeader(headerName, headerValue);
29148 this.xhr.onload = function()
29150 _this.xhrOnLoad(_this.xhr);
29153 this.xhr.onerror = function()
29155 _this.xhrOnError(_this.xhr);
29158 var formData = new FormData();
29160 formData.append('returnHTML', 'NO');
29163 formData.append('crop', crop);
29166 formData.append(this.paramName, file, file.name);
29173 if(this.fireEvent('prepare', this, formData, options) != false){
29175 if(options.manually){
29179 this.xhr.send(formData);
29183 this.uploadCancel();
29186 uploadCancel : function()
29192 this.delegates = [];
29194 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29201 renderPreview : function(file)
29203 if(typeof(file.target) != 'undefined' && file.target){
29207 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29209 var previewEl = this.managerEl.createChild({
29211 cls : 'roo-document-manager-preview',
29215 tooltip : file[this.toolTipName],
29216 cls : 'roo-document-manager-thumb',
29217 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29222 html : '<i class="fa fa-times-circle"></i>'
29227 var close = previewEl.select('button.close', true).first();
29229 close.on('click', this.onRemove, this, file);
29231 file.target = previewEl;
29233 var image = previewEl.select('img', true).first();
29237 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29239 image.on('click', this.onClick, this, file);
29241 this.fireEvent('previewrendered', this, file);
29247 onPreviewLoad : function(file, image)
29249 if(typeof(file.target) == 'undefined' || !file.target){
29253 var width = image.dom.naturalWidth || image.dom.width;
29254 var height = image.dom.naturalHeight || image.dom.height;
29256 if(width > height){
29257 file.target.addClass('wide');
29261 file.target.addClass('tall');
29266 uploadFromSource : function(file, crop)
29268 this.xhr = new XMLHttpRequest();
29270 this.managerEl.createChild({
29272 cls : 'roo-document-manager-loading',
29276 tooltip : file.name,
29277 cls : 'roo-document-manager-thumb',
29278 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29284 this.xhr.open(this.method, this.url, true);
29287 "Accept": "application/json",
29288 "Cache-Control": "no-cache",
29289 "X-Requested-With": "XMLHttpRequest"
29292 for (var headerName in headers) {
29293 var headerValue = headers[headerName];
29295 this.xhr.setRequestHeader(headerName, headerValue);
29301 this.xhr.onload = function()
29303 _this.xhrOnLoad(_this.xhr);
29306 this.xhr.onerror = function()
29308 _this.xhrOnError(_this.xhr);
29311 var formData = new FormData();
29313 formData.append('returnHTML', 'NO');
29315 formData.append('crop', crop);
29317 if(typeof(file.filename) != 'undefined'){
29318 formData.append('filename', file.filename);
29321 if(typeof(file.mimetype) != 'undefined'){
29322 formData.append('mimetype', file.mimetype);
29327 if(this.fireEvent('prepare', this, formData) != false){
29328 this.xhr.send(formData);
29338 * @class Roo.bootstrap.DocumentViewer
29339 * @extends Roo.bootstrap.Component
29340 * Bootstrap DocumentViewer class
29341 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29342 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29345 * Create a new DocumentViewer
29346 * @param {Object} config The config object
29349 Roo.bootstrap.DocumentViewer = function(config){
29350 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29355 * Fire after initEvent
29356 * @param {Roo.bootstrap.DocumentViewer} this
29362 * @param {Roo.bootstrap.DocumentViewer} this
29367 * Fire after download button
29368 * @param {Roo.bootstrap.DocumentViewer} this
29373 * Fire after trash button
29374 * @param {Roo.bootstrap.DocumentViewer} this
29381 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29383 showDownload : true,
29387 getAutoCreate : function()
29391 cls : 'roo-document-viewer',
29395 cls : 'roo-document-viewer-body',
29399 cls : 'roo-document-viewer-thumb',
29403 cls : 'roo-document-viewer-image'
29411 cls : 'roo-document-viewer-footer',
29414 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29418 cls : 'btn-group roo-document-viewer-download',
29422 cls : 'btn btn-default',
29423 html : '<i class="fa fa-download"></i>'
29429 cls : 'btn-group roo-document-viewer-trash',
29433 cls : 'btn btn-default',
29434 html : '<i class="fa fa-trash"></i>'
29447 initEvents : function()
29449 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29450 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29452 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29453 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29455 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29456 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29458 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29459 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29461 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29462 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29464 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29465 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29467 this.bodyEl.on('click', this.onClick, this);
29468 this.downloadBtn.on('click', this.onDownload, this);
29469 this.trashBtn.on('click', this.onTrash, this);
29471 this.downloadBtn.hide();
29472 this.trashBtn.hide();
29474 if(this.showDownload){
29475 this.downloadBtn.show();
29478 if(this.showTrash){
29479 this.trashBtn.show();
29482 if(!this.showDownload && !this.showTrash) {
29483 this.footerEl.hide();
29488 initial : function()
29490 this.fireEvent('initial', this);
29494 onClick : function(e)
29496 e.preventDefault();
29498 this.fireEvent('click', this);
29501 onDownload : function(e)
29503 e.preventDefault();
29505 this.fireEvent('download', this);
29508 onTrash : function(e)
29510 e.preventDefault();
29512 this.fireEvent('trash', this);
29524 * @class Roo.bootstrap.NavProgressBar
29525 * @extends Roo.bootstrap.Component
29526 * Bootstrap NavProgressBar class
29529 * Create a new nav progress bar
29530 * @param {Object} config The config object
29533 Roo.bootstrap.NavProgressBar = function(config){
29534 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29536 this.bullets = this.bullets || [];
29538 // Roo.bootstrap.NavProgressBar.register(this);
29542 * Fires when the active item changes
29543 * @param {Roo.bootstrap.NavProgressBar} this
29544 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29545 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29552 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29557 getAutoCreate : function()
29559 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29563 cls : 'roo-navigation-bar-group',
29567 cls : 'roo-navigation-top-bar'
29571 cls : 'roo-navigation-bullets-bar',
29575 cls : 'roo-navigation-bar'
29582 cls : 'roo-navigation-bottom-bar'
29592 initEvents: function()
29597 onRender : function(ct, position)
29599 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29601 if(this.bullets.length){
29602 Roo.each(this.bullets, function(b){
29611 addItem : function(cfg)
29613 var item = new Roo.bootstrap.NavProgressItem(cfg);
29615 item.parentId = this.id;
29616 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29619 var top = new Roo.bootstrap.Element({
29621 cls : 'roo-navigation-bar-text'
29624 var bottom = new Roo.bootstrap.Element({
29626 cls : 'roo-navigation-bar-text'
29629 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29630 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29632 var topText = new Roo.bootstrap.Element({
29634 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29637 var bottomText = new Roo.bootstrap.Element({
29639 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29642 topText.onRender(top.el, null);
29643 bottomText.onRender(bottom.el, null);
29646 item.bottomEl = bottom;
29649 this.barItems.push(item);
29654 getActive : function()
29656 var active = false;
29658 Roo.each(this.barItems, function(v){
29660 if (!v.isActive()) {
29672 setActiveItem : function(item)
29676 Roo.each(this.barItems, function(v){
29677 if (v.rid == item.rid) {
29681 if (v.isActive()) {
29682 v.setActive(false);
29687 item.setActive(true);
29689 this.fireEvent('changed', this, item, prev);
29692 getBarItem: function(rid)
29696 Roo.each(this.barItems, function(e) {
29697 if (e.rid != rid) {
29708 indexOfItem : function(item)
29712 Roo.each(this.barItems, function(v, i){
29714 if (v.rid != item.rid) {
29725 setActiveNext : function()
29727 var i = this.indexOfItem(this.getActive());
29729 if (i > this.barItems.length) {
29733 this.setActiveItem(this.barItems[i+1]);
29736 setActivePrev : function()
29738 var i = this.indexOfItem(this.getActive());
29744 this.setActiveItem(this.barItems[i-1]);
29747 format : function()
29749 if(!this.barItems.length){
29753 var width = 100 / this.barItems.length;
29755 Roo.each(this.barItems, function(i){
29756 i.el.setStyle('width', width + '%');
29757 i.topEl.el.setStyle('width', width + '%');
29758 i.bottomEl.el.setStyle('width', width + '%');
29767 * Nav Progress Item
29772 * @class Roo.bootstrap.NavProgressItem
29773 * @extends Roo.bootstrap.Component
29774 * Bootstrap NavProgressItem class
29775 * @cfg {String} rid the reference id
29776 * @cfg {Boolean} active (true|false) Is item active default false
29777 * @cfg {Boolean} disabled (true|false) Is item active default false
29778 * @cfg {String} html
29779 * @cfg {String} position (top|bottom) text position default bottom
29780 * @cfg {String} icon show icon instead of number
29783 * Create a new NavProgressItem
29784 * @param {Object} config The config object
29786 Roo.bootstrap.NavProgressItem = function(config){
29787 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29792 * The raw click event for the entire grid.
29793 * @param {Roo.bootstrap.NavProgressItem} this
29794 * @param {Roo.EventObject} e
29801 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29807 position : 'bottom',
29810 getAutoCreate : function()
29812 var iconCls = 'roo-navigation-bar-item-icon';
29814 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29818 cls: 'roo-navigation-bar-item',
29828 cfg.cls += ' active';
29831 cfg.cls += ' disabled';
29837 disable : function()
29839 this.setDisabled(true);
29842 enable : function()
29844 this.setDisabled(false);
29847 initEvents: function()
29849 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29851 this.iconEl.on('click', this.onClick, this);
29854 onClick : function(e)
29856 e.preventDefault();
29862 if(this.fireEvent('click', this, e) === false){
29866 this.parent().setActiveItem(this);
29869 isActive: function ()
29871 return this.active;
29874 setActive : function(state)
29876 if(this.active == state){
29880 this.active = state;
29883 this.el.addClass('active');
29887 this.el.removeClass('active');
29892 setDisabled : function(state)
29894 if(this.disabled == state){
29898 this.disabled = state;
29901 this.el.addClass('disabled');
29905 this.el.removeClass('disabled');
29908 tooltipEl : function()
29910 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29923 * @class Roo.bootstrap.FieldLabel
29924 * @extends Roo.bootstrap.Component
29925 * Bootstrap FieldLabel class
29926 * @cfg {String} html contents of the element
29927 * @cfg {String} tag tag of the element default label
29928 * @cfg {String} cls class of the element
29929 * @cfg {String} target label target
29930 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29931 * @cfg {String} invalidClass default "text-warning"
29932 * @cfg {String} validClass default "text-success"
29933 * @cfg {String} iconTooltip default "This field is required"
29934 * @cfg {String} indicatorpos (left|right) default left
29937 * Create a new FieldLabel
29938 * @param {Object} config The config object
29941 Roo.bootstrap.FieldLabel = function(config){
29942 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29947 * Fires after the field has been marked as invalid.
29948 * @param {Roo.form.FieldLabel} this
29949 * @param {String} msg The validation message
29954 * Fires after the field has been validated with no errors.
29955 * @param {Roo.form.FieldLabel} this
29961 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29968 invalidClass : 'has-warning',
29969 validClass : 'has-success',
29970 iconTooltip : 'This field is required',
29971 indicatorpos : 'left',
29973 getAutoCreate : function(){
29977 cls : 'roo-bootstrap-field-label ' + this.cls,
29982 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29983 tooltip : this.iconTooltip
29992 if(this.indicatorpos == 'right'){
29995 cls : 'roo-bootstrap-field-label ' + this.cls,
30004 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30005 tooltip : this.iconTooltip
30014 initEvents: function()
30016 Roo.bootstrap.Element.superclass.initEvents.call(this);
30018 this.indicator = this.indicatorEl();
30020 if(this.indicator){
30021 this.indicator.removeClass('visible');
30022 this.indicator.addClass('invisible');
30025 Roo.bootstrap.FieldLabel.register(this);
30028 indicatorEl : function()
30030 var indicator = this.el.select('i.roo-required-indicator',true).first();
30041 * Mark this field as valid
30043 markValid : function()
30045 if(this.indicator){
30046 this.indicator.removeClass('visible');
30047 this.indicator.addClass('invisible');
30050 this.el.removeClass(this.invalidClass);
30052 this.el.addClass(this.validClass);
30054 this.fireEvent('valid', this);
30058 * Mark this field as invalid
30059 * @param {String} msg The validation message
30061 markInvalid : function(msg)
30063 if(this.indicator){
30064 this.indicator.removeClass('invisible');
30065 this.indicator.addClass('visible');
30068 this.el.removeClass(this.validClass);
30070 this.el.addClass(this.invalidClass);
30072 this.fireEvent('invalid', this, msg);
30078 Roo.apply(Roo.bootstrap.FieldLabel, {
30083 * register a FieldLabel Group
30084 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30086 register : function(label)
30088 if(this.groups.hasOwnProperty(label.target)){
30092 this.groups[label.target] = label;
30096 * fetch a FieldLabel Group based on the target
30097 * @param {string} target
30098 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30100 get: function(target) {
30101 if (typeof(this.groups[target]) == 'undefined') {
30105 return this.groups[target] ;
30114 * page DateSplitField.
30120 * @class Roo.bootstrap.DateSplitField
30121 * @extends Roo.bootstrap.Component
30122 * Bootstrap DateSplitField class
30123 * @cfg {string} fieldLabel - the label associated
30124 * @cfg {Number} labelWidth set the width of label (0-12)
30125 * @cfg {String} labelAlign (top|left)
30126 * @cfg {Boolean} dayAllowBlank (true|false) default false
30127 * @cfg {Boolean} monthAllowBlank (true|false) default false
30128 * @cfg {Boolean} yearAllowBlank (true|false) default false
30129 * @cfg {string} dayPlaceholder
30130 * @cfg {string} monthPlaceholder
30131 * @cfg {string} yearPlaceholder
30132 * @cfg {string} dayFormat default 'd'
30133 * @cfg {string} monthFormat default 'm'
30134 * @cfg {string} yearFormat default 'Y'
30135 * @cfg {Number} labellg set the width of label (1-12)
30136 * @cfg {Number} labelmd set the width of label (1-12)
30137 * @cfg {Number} labelsm set the width of label (1-12)
30138 * @cfg {Number} labelxs set the width of label (1-12)
30142 * Create a new DateSplitField
30143 * @param {Object} config The config object
30146 Roo.bootstrap.DateSplitField = function(config){
30147 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30153 * getting the data of years
30154 * @param {Roo.bootstrap.DateSplitField} this
30155 * @param {Object} years
30160 * getting the data of days
30161 * @param {Roo.bootstrap.DateSplitField} this
30162 * @param {Object} days
30167 * Fires after the field has been marked as invalid.
30168 * @param {Roo.form.Field} this
30169 * @param {String} msg The validation message
30174 * Fires after the field has been validated with no errors.
30175 * @param {Roo.form.Field} this
30181 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30184 labelAlign : 'top',
30186 dayAllowBlank : false,
30187 monthAllowBlank : false,
30188 yearAllowBlank : false,
30189 dayPlaceholder : '',
30190 monthPlaceholder : '',
30191 yearPlaceholder : '',
30195 isFormField : true,
30201 getAutoCreate : function()
30205 cls : 'row roo-date-split-field-group',
30210 cls : 'form-hidden-field roo-date-split-field-group-value',
30216 var labelCls = 'col-md-12';
30217 var contentCls = 'col-md-4';
30219 if(this.fieldLabel){
30223 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30227 html : this.fieldLabel
30232 if(this.labelAlign == 'left'){
30234 if(this.labelWidth > 12){
30235 label.style = "width: " + this.labelWidth + 'px';
30238 if(this.labelWidth < 13 && this.labelmd == 0){
30239 this.labelmd = this.labelWidth;
30242 if(this.labellg > 0){
30243 labelCls = ' col-lg-' + this.labellg;
30244 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30247 if(this.labelmd > 0){
30248 labelCls = ' col-md-' + this.labelmd;
30249 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30252 if(this.labelsm > 0){
30253 labelCls = ' col-sm-' + this.labelsm;
30254 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30257 if(this.labelxs > 0){
30258 labelCls = ' col-xs-' + this.labelxs;
30259 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30263 label.cls += ' ' + labelCls;
30265 cfg.cn.push(label);
30268 Roo.each(['day', 'month', 'year'], function(t){
30271 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30278 inputEl: function ()
30280 return this.el.select('.roo-date-split-field-group-value', true).first();
30283 onRender : function(ct, position)
30287 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30289 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30291 this.dayField = new Roo.bootstrap.ComboBox({
30292 allowBlank : this.dayAllowBlank,
30293 alwaysQuery : true,
30294 displayField : 'value',
30297 forceSelection : true,
30299 placeholder : this.dayPlaceholder,
30300 selectOnFocus : true,
30301 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30302 triggerAction : 'all',
30304 valueField : 'value',
30305 store : new Roo.data.SimpleStore({
30306 data : (function() {
30308 _this.fireEvent('days', _this, days);
30311 fields : [ 'value' ]
30314 select : function (_self, record, index)
30316 _this.setValue(_this.getValue());
30321 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30323 this.monthField = new Roo.bootstrap.MonthField({
30324 after : '<i class=\"fa fa-calendar\"></i>',
30325 allowBlank : this.monthAllowBlank,
30326 placeholder : this.monthPlaceholder,
30329 render : function (_self)
30331 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30332 e.preventDefault();
30336 select : function (_self, oldvalue, newvalue)
30338 _this.setValue(_this.getValue());
30343 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30345 this.yearField = new Roo.bootstrap.ComboBox({
30346 allowBlank : this.yearAllowBlank,
30347 alwaysQuery : true,
30348 displayField : 'value',
30351 forceSelection : true,
30353 placeholder : this.yearPlaceholder,
30354 selectOnFocus : true,
30355 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30356 triggerAction : 'all',
30358 valueField : 'value',
30359 store : new Roo.data.SimpleStore({
30360 data : (function() {
30362 _this.fireEvent('years', _this, years);
30365 fields : [ 'value' ]
30368 select : function (_self, record, index)
30370 _this.setValue(_this.getValue());
30375 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30378 setValue : function(v, format)
30380 this.inputEl.dom.value = v;
30382 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30384 var d = Date.parseDate(v, f);
30391 this.setDay(d.format(this.dayFormat));
30392 this.setMonth(d.format(this.monthFormat));
30393 this.setYear(d.format(this.yearFormat));
30400 setDay : function(v)
30402 this.dayField.setValue(v);
30403 this.inputEl.dom.value = this.getValue();
30408 setMonth : function(v)
30410 this.monthField.setValue(v, true);
30411 this.inputEl.dom.value = this.getValue();
30416 setYear : function(v)
30418 this.yearField.setValue(v);
30419 this.inputEl.dom.value = this.getValue();
30424 getDay : function()
30426 return this.dayField.getValue();
30429 getMonth : function()
30431 return this.monthField.getValue();
30434 getYear : function()
30436 return this.yearField.getValue();
30439 getValue : function()
30441 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30443 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30453 this.inputEl.dom.value = '';
30458 validate : function()
30460 var d = this.dayField.validate();
30461 var m = this.monthField.validate();
30462 var y = this.yearField.validate();
30467 (!this.dayAllowBlank && !d) ||
30468 (!this.monthAllowBlank && !m) ||
30469 (!this.yearAllowBlank && !y)
30474 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30483 this.markInvalid();
30488 markValid : function()
30491 var label = this.el.select('label', true).first();
30492 var icon = this.el.select('i.fa-star', true).first();
30498 this.fireEvent('valid', this);
30502 * Mark this field as invalid
30503 * @param {String} msg The validation message
30505 markInvalid : function(msg)
30508 var label = this.el.select('label', true).first();
30509 var icon = this.el.select('i.fa-star', true).first();
30511 if(label && !icon){
30512 this.el.select('.roo-date-split-field-label', true).createChild({
30514 cls : 'text-danger fa fa-lg fa-star',
30515 tooltip : 'This field is required',
30516 style : 'margin-right:5px;'
30520 this.fireEvent('invalid', this, msg);
30523 clearInvalid : function()
30525 var label = this.el.select('label', true).first();
30526 var icon = this.el.select('i.fa-star', true).first();
30532 this.fireEvent('valid', this);
30535 getName: function()
30545 * http://masonry.desandro.com
30547 * The idea is to render all the bricks based on vertical width...
30549 * The original code extends 'outlayer' - we might need to use that....
30555 * @class Roo.bootstrap.LayoutMasonry
30556 * @extends Roo.bootstrap.Component
30557 * Bootstrap Layout Masonry class
30560 * Create a new Element
30561 * @param {Object} config The config object
30564 Roo.bootstrap.LayoutMasonry = function(config){
30566 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30570 Roo.bootstrap.LayoutMasonry.register(this);
30576 * Fire after layout the items
30577 * @param {Roo.bootstrap.LayoutMasonry} this
30578 * @param {Roo.EventObject} e
30585 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30588 * @cfg {Boolean} isLayoutInstant = no animation?
30590 isLayoutInstant : false, // needed?
30593 * @cfg {Number} boxWidth width of the columns
30598 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30603 * @cfg {Number} padWidth padding below box..
30608 * @cfg {Number} gutter gutter width..
30613 * @cfg {Number} maxCols maximum number of columns
30619 * @cfg {Boolean} isAutoInitial defalut true
30621 isAutoInitial : true,
30626 * @cfg {Boolean} isHorizontal defalut false
30628 isHorizontal : false,
30630 currentSize : null,
30636 bricks: null, //CompositeElement
30640 _isLayoutInited : false,
30642 // isAlternative : false, // only use for vertical layout...
30645 * @cfg {Number} alternativePadWidth padding below box..
30647 alternativePadWidth : 50,
30649 selectedBrick : [],
30651 getAutoCreate : function(){
30653 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30657 cls: 'blog-masonary-wrapper ' + this.cls,
30659 cls : 'mas-boxes masonary'
30666 getChildContainer: function( )
30668 if (this.boxesEl) {
30669 return this.boxesEl;
30672 this.boxesEl = this.el.select('.mas-boxes').first();
30674 return this.boxesEl;
30678 initEvents : function()
30682 if(this.isAutoInitial){
30683 Roo.log('hook children rendered');
30684 this.on('childrenrendered', function() {
30685 Roo.log('children rendered');
30691 initial : function()
30693 this.selectedBrick = [];
30695 this.currentSize = this.el.getBox(true);
30697 Roo.EventManager.onWindowResize(this.resize, this);
30699 if(!this.isAutoInitial){
30707 //this.layout.defer(500,this);
30711 resize : function()
30713 var cs = this.el.getBox(true);
30716 this.currentSize.width == cs.width &&
30717 this.currentSize.x == cs.x &&
30718 this.currentSize.height == cs.height &&
30719 this.currentSize.y == cs.y
30721 Roo.log("no change in with or X or Y");
30725 this.currentSize = cs;
30731 layout : function()
30733 this._resetLayout();
30735 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30737 this.layoutItems( isInstant );
30739 this._isLayoutInited = true;
30741 this.fireEvent('layout', this);
30745 _resetLayout : function()
30747 if(this.isHorizontal){
30748 this.horizontalMeasureColumns();
30752 this.verticalMeasureColumns();
30756 verticalMeasureColumns : function()
30758 this.getContainerWidth();
30760 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30761 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30765 var boxWidth = this.boxWidth + this.padWidth;
30767 if(this.containerWidth < this.boxWidth){
30768 boxWidth = this.containerWidth
30771 var containerWidth = this.containerWidth;
30773 var cols = Math.floor(containerWidth / boxWidth);
30775 this.cols = Math.max( cols, 1 );
30777 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30779 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30781 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30783 this.colWidth = boxWidth + avail - this.padWidth;
30785 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30786 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30789 horizontalMeasureColumns : function()
30791 this.getContainerWidth();
30793 var boxWidth = this.boxWidth;
30795 if(this.containerWidth < boxWidth){
30796 boxWidth = this.containerWidth;
30799 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30801 this.el.setHeight(boxWidth);
30805 getContainerWidth : function()
30807 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30810 layoutItems : function( isInstant )
30812 Roo.log(this.bricks);
30814 var items = Roo.apply([], this.bricks);
30816 if(this.isHorizontal){
30817 this._horizontalLayoutItems( items , isInstant );
30821 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30822 // this._verticalAlternativeLayoutItems( items , isInstant );
30826 this._verticalLayoutItems( items , isInstant );
30830 _verticalLayoutItems : function ( items , isInstant)
30832 if ( !items || !items.length ) {
30837 ['xs', 'xs', 'xs', 'tall'],
30838 ['xs', 'xs', 'tall'],
30839 ['xs', 'xs', 'sm'],
30840 ['xs', 'xs', 'xs'],
30846 ['sm', 'xs', 'xs'],
30850 ['tall', 'xs', 'xs', 'xs'],
30851 ['tall', 'xs', 'xs'],
30863 Roo.each(items, function(item, k){
30865 switch (item.size) {
30866 // these layouts take up a full box,
30877 boxes.push([item]);
30900 var filterPattern = function(box, length)
30908 var pattern = box.slice(0, length);
30912 Roo.each(pattern, function(i){
30913 format.push(i.size);
30916 Roo.each(standard, function(s){
30918 if(String(s) != String(format)){
30927 if(!match && length == 1){
30932 filterPattern(box, length - 1);
30936 queue.push(pattern);
30938 box = box.slice(length, box.length);
30940 filterPattern(box, 4);
30946 Roo.each(boxes, function(box, k){
30952 if(box.length == 1){
30957 filterPattern(box, 4);
30961 this._processVerticalLayoutQueue( queue, isInstant );
30965 // _verticalAlternativeLayoutItems : function( items , isInstant )
30967 // if ( !items || !items.length ) {
30971 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30975 _horizontalLayoutItems : function ( items , isInstant)
30977 if ( !items || !items.length || items.length < 3) {
30983 var eItems = items.slice(0, 3);
30985 items = items.slice(3, items.length);
30988 ['xs', 'xs', 'xs', 'wide'],
30989 ['xs', 'xs', 'wide'],
30990 ['xs', 'xs', 'sm'],
30991 ['xs', 'xs', 'xs'],
30997 ['sm', 'xs', 'xs'],
31001 ['wide', 'xs', 'xs', 'xs'],
31002 ['wide', 'xs', 'xs'],
31015 Roo.each(items, function(item, k){
31017 switch (item.size) {
31028 boxes.push([item]);
31052 var filterPattern = function(box, length)
31060 var pattern = box.slice(0, length);
31064 Roo.each(pattern, function(i){
31065 format.push(i.size);
31068 Roo.each(standard, function(s){
31070 if(String(s) != String(format)){
31079 if(!match && length == 1){
31084 filterPattern(box, length - 1);
31088 queue.push(pattern);
31090 box = box.slice(length, box.length);
31092 filterPattern(box, 4);
31098 Roo.each(boxes, function(box, k){
31104 if(box.length == 1){
31109 filterPattern(box, 4);
31116 var pos = this.el.getBox(true);
31120 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31122 var hit_end = false;
31124 Roo.each(queue, function(box){
31128 Roo.each(box, function(b){
31130 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31140 Roo.each(box, function(b){
31142 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31145 mx = Math.max(mx, b.x);
31149 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31153 Roo.each(box, function(b){
31155 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31169 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31172 /** Sets position of item in DOM
31173 * @param {Element} item
31174 * @param {Number} x - horizontal position
31175 * @param {Number} y - vertical position
31176 * @param {Boolean} isInstant - disables transitions
31178 _processVerticalLayoutQueue : function( queue, isInstant )
31180 var pos = this.el.getBox(true);
31185 for (var i = 0; i < this.cols; i++){
31189 Roo.each(queue, function(box, k){
31191 var col = k % this.cols;
31193 Roo.each(box, function(b,kk){
31195 b.el.position('absolute');
31197 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31198 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31200 if(b.size == 'md-left' || b.size == 'md-right'){
31201 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31202 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31205 b.el.setWidth(width);
31206 b.el.setHeight(height);
31208 b.el.select('iframe',true).setSize(width,height);
31212 for (var i = 0; i < this.cols; i++){
31214 if(maxY[i] < maxY[col]){
31219 col = Math.min(col, i);
31223 x = pos.x + col * (this.colWidth + this.padWidth);
31227 var positions = [];
31229 switch (box.length){
31231 positions = this.getVerticalOneBoxColPositions(x, y, box);
31234 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31237 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31240 positions = this.getVerticalFourBoxColPositions(x, y, box);
31246 Roo.each(box, function(b,kk){
31248 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31250 var sz = b.el.getSize();
31252 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31260 for (var i = 0; i < this.cols; i++){
31261 mY = Math.max(mY, maxY[i]);
31264 this.el.setHeight(mY - pos.y);
31268 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31270 // var pos = this.el.getBox(true);
31273 // var maxX = pos.right;
31275 // var maxHeight = 0;
31277 // Roo.each(items, function(item, k){
31281 // item.el.position('absolute');
31283 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31285 // item.el.setWidth(width);
31287 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31289 // item.el.setHeight(height);
31292 // item.el.setXY([x, y], isInstant ? false : true);
31294 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31297 // y = y + height + this.alternativePadWidth;
31299 // maxHeight = maxHeight + height + this.alternativePadWidth;
31303 // this.el.setHeight(maxHeight);
31307 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31309 var pos = this.el.getBox(true);
31314 var maxX = pos.right;
31316 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31318 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31320 Roo.each(queue, function(box, k){
31322 Roo.each(box, function(b, kk){
31324 b.el.position('absolute');
31326 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31327 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31329 if(b.size == 'md-left' || b.size == 'md-right'){
31330 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31331 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31334 b.el.setWidth(width);
31335 b.el.setHeight(height);
31343 var positions = [];
31345 switch (box.length){
31347 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31350 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31353 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31356 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31362 Roo.each(box, function(b,kk){
31364 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31366 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31374 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31376 Roo.each(eItems, function(b,k){
31378 b.size = (k == 0) ? 'sm' : 'xs';
31379 b.x = (k == 0) ? 2 : 1;
31380 b.y = (k == 0) ? 2 : 1;
31382 b.el.position('absolute');
31384 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31386 b.el.setWidth(width);
31388 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31390 b.el.setHeight(height);
31394 var positions = [];
31397 x : maxX - this.unitWidth * 2 - this.gutter,
31402 x : maxX - this.unitWidth,
31403 y : minY + (this.unitWidth + this.gutter) * 2
31407 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31411 Roo.each(eItems, function(b,k){
31413 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31419 getVerticalOneBoxColPositions : function(x, y, box)
31423 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31425 if(box[0].size == 'md-left'){
31429 if(box[0].size == 'md-right'){
31434 x : x + (this.unitWidth + this.gutter) * rand,
31441 getVerticalTwoBoxColPositions : function(x, y, box)
31445 if(box[0].size == 'xs'){
31449 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31453 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31467 x : x + (this.unitWidth + this.gutter) * 2,
31468 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31475 getVerticalThreeBoxColPositions : function(x, y, box)
31479 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31487 x : x + (this.unitWidth + this.gutter) * 1,
31492 x : x + (this.unitWidth + this.gutter) * 2,
31500 if(box[0].size == 'xs' && box[1].size == 'xs'){
31509 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31513 x : x + (this.unitWidth + this.gutter) * 1,
31527 x : x + (this.unitWidth + this.gutter) * 2,
31532 x : x + (this.unitWidth + this.gutter) * 2,
31533 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31540 getVerticalFourBoxColPositions : function(x, y, box)
31544 if(box[0].size == 'xs'){
31553 y : y + (this.unitHeight + this.gutter) * 1
31558 y : y + (this.unitHeight + this.gutter) * 2
31562 x : x + (this.unitWidth + this.gutter) * 1,
31576 x : x + (this.unitWidth + this.gutter) * 2,
31581 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31582 y : y + (this.unitHeight + this.gutter) * 1
31586 x : x + (this.unitWidth + this.gutter) * 2,
31587 y : y + (this.unitWidth + this.gutter) * 2
31594 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31598 if(box[0].size == 'md-left'){
31600 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31607 if(box[0].size == 'md-right'){
31609 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31610 y : minY + (this.unitWidth + this.gutter) * 1
31616 var rand = Math.floor(Math.random() * (4 - box[0].y));
31619 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31620 y : minY + (this.unitWidth + this.gutter) * rand
31627 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31631 if(box[0].size == 'xs'){
31634 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31639 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31640 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31648 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31653 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31654 y : minY + (this.unitWidth + this.gutter) * 2
31661 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31665 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31668 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31673 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31674 y : minY + (this.unitWidth + this.gutter) * 1
31678 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31679 y : minY + (this.unitWidth + this.gutter) * 2
31686 if(box[0].size == 'xs' && box[1].size == 'xs'){
31689 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31694 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31699 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31700 y : minY + (this.unitWidth + this.gutter) * 1
31708 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31713 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31714 y : minY + (this.unitWidth + this.gutter) * 2
31718 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31719 y : minY + (this.unitWidth + this.gutter) * 2
31726 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31730 if(box[0].size == 'xs'){
31733 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31738 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31743 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),
31748 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31749 y : minY + (this.unitWidth + this.gutter) * 1
31757 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31762 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31763 y : minY + (this.unitWidth + this.gutter) * 2
31767 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31768 y : minY + (this.unitWidth + this.gutter) * 2
31772 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),
31773 y : minY + (this.unitWidth + this.gutter) * 2
31781 * remove a Masonry Brick
31782 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31784 removeBrick : function(brick_id)
31790 for (var i = 0; i<this.bricks.length; i++) {
31791 if (this.bricks[i].id == brick_id) {
31792 this.bricks.splice(i,1);
31793 this.el.dom.removeChild(Roo.get(brick_id).dom);
31800 * adds a Masonry Brick
31801 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31803 addBrick : function(cfg)
31805 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31806 //this.register(cn);
31807 cn.parentId = this.id;
31808 cn.onRender(this.el, null);
31813 * register a Masonry Brick
31814 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31817 register : function(brick)
31819 this.bricks.push(brick);
31820 brick.masonryId = this.id;
31824 * clear all the Masonry Brick
31826 clearAll : function()
31829 //this.getChildContainer().dom.innerHTML = "";
31830 this.el.dom.innerHTML = '';
31833 getSelected : function()
31835 if (!this.selectedBrick) {
31839 return this.selectedBrick;
31843 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31847 * register a Masonry Layout
31848 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31851 register : function(layout)
31853 this.groups[layout.id] = layout;
31856 * fetch a Masonry Layout based on the masonry layout ID
31857 * @param {string} the masonry layout to add
31858 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31861 get: function(layout_id) {
31862 if (typeof(this.groups[layout_id]) == 'undefined') {
31865 return this.groups[layout_id] ;
31877 * http://masonry.desandro.com
31879 * The idea is to render all the bricks based on vertical width...
31881 * The original code extends 'outlayer' - we might need to use that....
31887 * @class Roo.bootstrap.LayoutMasonryAuto
31888 * @extends Roo.bootstrap.Component
31889 * Bootstrap Layout Masonry class
31892 * Create a new Element
31893 * @param {Object} config The config object
31896 Roo.bootstrap.LayoutMasonryAuto = function(config){
31897 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31900 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31903 * @cfg {Boolean} isFitWidth - resize the width..
31905 isFitWidth : false, // options..
31907 * @cfg {Boolean} isOriginLeft = left align?
31909 isOriginLeft : true,
31911 * @cfg {Boolean} isOriginTop = top align?
31913 isOriginTop : false,
31915 * @cfg {Boolean} isLayoutInstant = no animation?
31917 isLayoutInstant : false, // needed?
31919 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31921 isResizingContainer : true,
31923 * @cfg {Number} columnWidth width of the columns
31929 * @cfg {Number} maxCols maximum number of columns
31934 * @cfg {Number} padHeight padding below box..
31940 * @cfg {Boolean} isAutoInitial defalut true
31943 isAutoInitial : true,
31949 initialColumnWidth : 0,
31950 currentSize : null,
31952 colYs : null, // array.
31959 bricks: null, //CompositeElement
31960 cols : 0, // array?
31961 // element : null, // wrapped now this.el
31962 _isLayoutInited : null,
31965 getAutoCreate : function(){
31969 cls: 'blog-masonary-wrapper ' + this.cls,
31971 cls : 'mas-boxes masonary'
31978 getChildContainer: function( )
31980 if (this.boxesEl) {
31981 return this.boxesEl;
31984 this.boxesEl = this.el.select('.mas-boxes').first();
31986 return this.boxesEl;
31990 initEvents : function()
31994 if(this.isAutoInitial){
31995 Roo.log('hook children rendered');
31996 this.on('childrenrendered', function() {
31997 Roo.log('children rendered');
32004 initial : function()
32006 this.reloadItems();
32008 this.currentSize = this.el.getBox(true);
32010 /// was window resize... - let's see if this works..
32011 Roo.EventManager.onWindowResize(this.resize, this);
32013 if(!this.isAutoInitial){
32018 this.layout.defer(500,this);
32021 reloadItems: function()
32023 this.bricks = this.el.select('.masonry-brick', true);
32025 this.bricks.each(function(b) {
32026 //Roo.log(b.getSize());
32027 if (!b.attr('originalwidth')) {
32028 b.attr('originalwidth', b.getSize().width);
32033 Roo.log(this.bricks.elements.length);
32036 resize : function()
32039 var cs = this.el.getBox(true);
32041 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32042 Roo.log("no change in with or X");
32045 this.currentSize = cs;
32049 layout : function()
32052 this._resetLayout();
32053 //this._manageStamps();
32055 // don't animate first layout
32056 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32057 this.layoutItems( isInstant );
32059 // flag for initalized
32060 this._isLayoutInited = true;
32063 layoutItems : function( isInstant )
32065 //var items = this._getItemsForLayout( this.items );
32066 // original code supports filtering layout items.. we just ignore it..
32068 this._layoutItems( this.bricks , isInstant );
32070 this._postLayout();
32072 _layoutItems : function ( items , isInstant)
32074 //this.fireEvent( 'layout', this, items );
32077 if ( !items || !items.elements.length ) {
32078 // no items, emit event with empty array
32083 items.each(function(item) {
32084 Roo.log("layout item");
32086 // get x/y object from method
32087 var position = this._getItemLayoutPosition( item );
32089 position.item = item;
32090 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32091 queue.push( position );
32094 this._processLayoutQueue( queue );
32096 /** Sets position of item in DOM
32097 * @param {Element} item
32098 * @param {Number} x - horizontal position
32099 * @param {Number} y - vertical position
32100 * @param {Boolean} isInstant - disables transitions
32102 _processLayoutQueue : function( queue )
32104 for ( var i=0, len = queue.length; i < len; i++ ) {
32105 var obj = queue[i];
32106 obj.item.position('absolute');
32107 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32113 * Any logic you want to do after each layout,
32114 * i.e. size the container
32116 _postLayout : function()
32118 this.resizeContainer();
32121 resizeContainer : function()
32123 if ( !this.isResizingContainer ) {
32126 var size = this._getContainerSize();
32128 this.el.setSize(size.width,size.height);
32129 this.boxesEl.setSize(size.width,size.height);
32135 _resetLayout : function()
32137 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32138 this.colWidth = this.el.getWidth();
32139 //this.gutter = this.el.getWidth();
32141 this.measureColumns();
32147 this.colYs.push( 0 );
32153 measureColumns : function()
32155 this.getContainerWidth();
32156 // if columnWidth is 0, default to outerWidth of first item
32157 if ( !this.columnWidth ) {
32158 var firstItem = this.bricks.first();
32159 Roo.log(firstItem);
32160 this.columnWidth = this.containerWidth;
32161 if (firstItem && firstItem.attr('originalwidth') ) {
32162 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32164 // columnWidth fall back to item of first element
32165 Roo.log("set column width?");
32166 this.initialColumnWidth = this.columnWidth ;
32168 // if first elem has no width, default to size of container
32173 if (this.initialColumnWidth) {
32174 this.columnWidth = this.initialColumnWidth;
32179 // column width is fixed at the top - however if container width get's smaller we should
32182 // this bit calcs how man columns..
32184 var columnWidth = this.columnWidth += this.gutter;
32186 // calculate columns
32187 var containerWidth = this.containerWidth + this.gutter;
32189 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32190 // fix rounding errors, typically with gutters
32191 var excess = columnWidth - containerWidth % columnWidth;
32194 // if overshoot is less than a pixel, round up, otherwise floor it
32195 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32196 cols = Math[ mathMethod ]( cols );
32197 this.cols = Math.max( cols, 1 );
32198 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32200 // padding positioning..
32201 var totalColWidth = this.cols * this.columnWidth;
32202 var padavail = this.containerWidth - totalColWidth;
32203 // so for 2 columns - we need 3 'pads'
32205 var padNeeded = (1+this.cols) * this.padWidth;
32207 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32209 this.columnWidth += padExtra
32210 //this.padWidth = Math.floor(padavail / ( this.cols));
32212 // adjust colum width so that padding is fixed??
32214 // we have 3 columns ... total = width * 3
32215 // we have X left over... that should be used by
32217 //if (this.expandC) {
32225 getContainerWidth : function()
32227 /* // container is parent if fit width
32228 var container = this.isFitWidth ? this.element.parentNode : this.element;
32229 // check that this.size and size are there
32230 // IE8 triggers resize on body size change, so they might not be
32232 var size = getSize( container ); //FIXME
32233 this.containerWidth = size && size.innerWidth; //FIXME
32236 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32240 _getItemLayoutPosition : function( item ) // what is item?
32242 // we resize the item to our columnWidth..
32244 item.setWidth(this.columnWidth);
32245 item.autoBoxAdjust = false;
32247 var sz = item.getSize();
32249 // how many columns does this brick span
32250 var remainder = this.containerWidth % this.columnWidth;
32252 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32253 // round if off by 1 pixel, otherwise use ceil
32254 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32255 colSpan = Math.min( colSpan, this.cols );
32257 // normally this should be '1' as we dont' currently allow multi width columns..
32259 var colGroup = this._getColGroup( colSpan );
32260 // get the minimum Y value from the columns
32261 var minimumY = Math.min.apply( Math, colGroup );
32262 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32264 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32266 // position the brick
32268 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32269 y: this.currentSize.y + minimumY + this.padHeight
32273 // apply setHeight to necessary columns
32274 var setHeight = minimumY + sz.height + this.padHeight;
32275 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32277 var setSpan = this.cols + 1 - colGroup.length;
32278 for ( var i = 0; i < setSpan; i++ ) {
32279 this.colYs[ shortColIndex + i ] = setHeight ;
32286 * @param {Number} colSpan - number of columns the element spans
32287 * @returns {Array} colGroup
32289 _getColGroup : function( colSpan )
32291 if ( colSpan < 2 ) {
32292 // if brick spans only one column, use all the column Ys
32297 // how many different places could this brick fit horizontally
32298 var groupCount = this.cols + 1 - colSpan;
32299 // for each group potential horizontal position
32300 for ( var i = 0; i < groupCount; i++ ) {
32301 // make an array of colY values for that one group
32302 var groupColYs = this.colYs.slice( i, i + colSpan );
32303 // and get the max value of the array
32304 colGroup[i] = Math.max.apply( Math, groupColYs );
32309 _manageStamp : function( stamp )
32311 var stampSize = stamp.getSize();
32312 var offset = stamp.getBox();
32313 // get the columns that this stamp affects
32314 var firstX = this.isOriginLeft ? offset.x : offset.right;
32315 var lastX = firstX + stampSize.width;
32316 var firstCol = Math.floor( firstX / this.columnWidth );
32317 firstCol = Math.max( 0, firstCol );
32319 var lastCol = Math.floor( lastX / this.columnWidth );
32320 // lastCol should not go over if multiple of columnWidth #425
32321 lastCol -= lastX % this.columnWidth ? 0 : 1;
32322 lastCol = Math.min( this.cols - 1, lastCol );
32324 // set colYs to bottom of the stamp
32325 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32328 for ( var i = firstCol; i <= lastCol; i++ ) {
32329 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32334 _getContainerSize : function()
32336 this.maxY = Math.max.apply( Math, this.colYs );
32341 if ( this.isFitWidth ) {
32342 size.width = this._getContainerFitWidth();
32348 _getContainerFitWidth : function()
32350 var unusedCols = 0;
32351 // count unused columns
32354 if ( this.colYs[i] !== 0 ) {
32359 // fit container to columns that have been used
32360 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32363 needsResizeLayout : function()
32365 var previousWidth = this.containerWidth;
32366 this.getContainerWidth();
32367 return previousWidth !== this.containerWidth;
32382 * @class Roo.bootstrap.MasonryBrick
32383 * @extends Roo.bootstrap.Component
32384 * Bootstrap MasonryBrick class
32387 * Create a new MasonryBrick
32388 * @param {Object} config The config object
32391 Roo.bootstrap.MasonryBrick = function(config){
32393 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32395 Roo.bootstrap.MasonryBrick.register(this);
32401 * When a MasonryBrick is clcik
32402 * @param {Roo.bootstrap.MasonryBrick} this
32403 * @param {Roo.EventObject} e
32409 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32412 * @cfg {String} title
32416 * @cfg {String} html
32420 * @cfg {String} bgimage
32424 * @cfg {String} videourl
32428 * @cfg {String} cls
32432 * @cfg {String} href
32436 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32441 * @cfg {String} placetitle (center|bottom)
32446 * @cfg {Boolean} isFitContainer defalut true
32448 isFitContainer : true,
32451 * @cfg {Boolean} preventDefault defalut false
32453 preventDefault : false,
32456 * @cfg {Boolean} inverse defalut false
32458 maskInverse : false,
32460 getAutoCreate : function()
32462 if(!this.isFitContainer){
32463 return this.getSplitAutoCreate();
32466 var cls = 'masonry-brick masonry-brick-full';
32468 if(this.href.length){
32469 cls += ' masonry-brick-link';
32472 if(this.bgimage.length){
32473 cls += ' masonry-brick-image';
32476 if(this.maskInverse){
32477 cls += ' mask-inverse';
32480 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32481 cls += ' enable-mask';
32485 cls += ' masonry-' + this.size + '-brick';
32488 if(this.placetitle.length){
32490 switch (this.placetitle) {
32492 cls += ' masonry-center-title';
32495 cls += ' masonry-bottom-title';
32502 if(!this.html.length && !this.bgimage.length){
32503 cls += ' masonry-center-title';
32506 if(!this.html.length && this.bgimage.length){
32507 cls += ' masonry-bottom-title';
32512 cls += ' ' + this.cls;
32516 tag: (this.href.length) ? 'a' : 'div',
32521 cls: 'masonry-brick-mask'
32525 cls: 'masonry-brick-paragraph',
32531 if(this.href.length){
32532 cfg.href = this.href;
32535 var cn = cfg.cn[1].cn;
32537 if(this.title.length){
32540 cls: 'masonry-brick-title',
32545 if(this.html.length){
32548 cls: 'masonry-brick-text',
32553 if (!this.title.length && !this.html.length) {
32554 cfg.cn[1].cls += ' hide';
32557 if(this.bgimage.length){
32560 cls: 'masonry-brick-image-view',
32565 if(this.videourl.length){
32566 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32567 // youtube support only?
32570 cls: 'masonry-brick-image-view',
32573 allowfullscreen : true
32581 getSplitAutoCreate : function()
32583 var cls = 'masonry-brick masonry-brick-split';
32585 if(this.href.length){
32586 cls += ' masonry-brick-link';
32589 if(this.bgimage.length){
32590 cls += ' masonry-brick-image';
32594 cls += ' masonry-' + this.size + '-brick';
32597 switch (this.placetitle) {
32599 cls += ' masonry-center-title';
32602 cls += ' masonry-bottom-title';
32605 if(!this.bgimage.length){
32606 cls += ' masonry-center-title';
32609 if(this.bgimage.length){
32610 cls += ' masonry-bottom-title';
32616 cls += ' ' + this.cls;
32620 tag: (this.href.length) ? 'a' : 'div',
32625 cls: 'masonry-brick-split-head',
32629 cls: 'masonry-brick-paragraph',
32636 cls: 'masonry-brick-split-body',
32642 if(this.href.length){
32643 cfg.href = this.href;
32646 if(this.title.length){
32647 cfg.cn[0].cn[0].cn.push({
32649 cls: 'masonry-brick-title',
32654 if(this.html.length){
32655 cfg.cn[1].cn.push({
32657 cls: 'masonry-brick-text',
32662 if(this.bgimage.length){
32663 cfg.cn[0].cn.push({
32665 cls: 'masonry-brick-image-view',
32670 if(this.videourl.length){
32671 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32672 // youtube support only?
32673 cfg.cn[0].cn.cn.push({
32675 cls: 'masonry-brick-image-view',
32678 allowfullscreen : true
32685 initEvents: function()
32687 switch (this.size) {
32720 this.el.on('touchstart', this.onTouchStart, this);
32721 this.el.on('touchmove', this.onTouchMove, this);
32722 this.el.on('touchend', this.onTouchEnd, this);
32723 this.el.on('contextmenu', this.onContextMenu, this);
32725 this.el.on('mouseenter' ,this.enter, this);
32726 this.el.on('mouseleave', this.leave, this);
32727 this.el.on('click', this.onClick, this);
32730 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32731 this.parent().bricks.push(this);
32736 onClick: function(e, el)
32738 var time = this.endTimer - this.startTimer;
32739 // Roo.log(e.preventDefault());
32742 e.preventDefault();
32747 if(!this.preventDefault){
32751 e.preventDefault();
32753 if (this.activeClass != '') {
32754 this.selectBrick();
32757 this.fireEvent('click', this, e);
32760 enter: function(e, el)
32762 e.preventDefault();
32764 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32768 if(this.bgimage.length && this.html.length){
32769 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32773 leave: function(e, el)
32775 e.preventDefault();
32777 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32781 if(this.bgimage.length && this.html.length){
32782 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32786 onTouchStart: function(e, el)
32788 // e.preventDefault();
32790 this.touchmoved = false;
32792 if(!this.isFitContainer){
32796 if(!this.bgimage.length || !this.html.length){
32800 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32802 this.timer = new Date().getTime();
32806 onTouchMove: function(e, el)
32808 this.touchmoved = true;
32811 onContextMenu : function(e,el)
32813 e.preventDefault();
32814 e.stopPropagation();
32818 onTouchEnd: function(e, el)
32820 // e.preventDefault();
32822 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32829 if(!this.bgimage.length || !this.html.length){
32831 if(this.href.length){
32832 window.location.href = this.href;
32838 if(!this.isFitContainer){
32842 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32844 window.location.href = this.href;
32847 //selection on single brick only
32848 selectBrick : function() {
32850 if (!this.parentId) {
32854 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32855 var index = m.selectedBrick.indexOf(this.id);
32858 m.selectedBrick.splice(index,1);
32859 this.el.removeClass(this.activeClass);
32863 for(var i = 0; i < m.selectedBrick.length; i++) {
32864 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32865 b.el.removeClass(b.activeClass);
32868 m.selectedBrick = [];
32870 m.selectedBrick.push(this.id);
32871 this.el.addClass(this.activeClass);
32875 isSelected : function(){
32876 return this.el.hasClass(this.activeClass);
32881 Roo.apply(Roo.bootstrap.MasonryBrick, {
32884 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32886 * register a Masonry Brick
32887 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32890 register : function(brick)
32892 //this.groups[brick.id] = brick;
32893 this.groups.add(brick.id, brick);
32896 * fetch a masonry brick based on the masonry brick ID
32897 * @param {string} the masonry brick to add
32898 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32901 get: function(brick_id)
32903 // if (typeof(this.groups[brick_id]) == 'undefined') {
32906 // return this.groups[brick_id] ;
32908 if(this.groups.key(brick_id)) {
32909 return this.groups.key(brick_id);
32927 * @class Roo.bootstrap.Brick
32928 * @extends Roo.bootstrap.Component
32929 * Bootstrap Brick class
32932 * Create a new Brick
32933 * @param {Object} config The config object
32936 Roo.bootstrap.Brick = function(config){
32937 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32943 * When a Brick is click
32944 * @param {Roo.bootstrap.Brick} this
32945 * @param {Roo.EventObject} e
32951 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32954 * @cfg {String} title
32958 * @cfg {String} html
32962 * @cfg {String} bgimage
32966 * @cfg {String} cls
32970 * @cfg {String} href
32974 * @cfg {String} video
32978 * @cfg {Boolean} square
32982 getAutoCreate : function()
32984 var cls = 'roo-brick';
32986 if(this.href.length){
32987 cls += ' roo-brick-link';
32990 if(this.bgimage.length){
32991 cls += ' roo-brick-image';
32994 if(!this.html.length && !this.bgimage.length){
32995 cls += ' roo-brick-center-title';
32998 if(!this.html.length && this.bgimage.length){
32999 cls += ' roo-brick-bottom-title';
33003 cls += ' ' + this.cls;
33007 tag: (this.href.length) ? 'a' : 'div',
33012 cls: 'roo-brick-paragraph',
33018 if(this.href.length){
33019 cfg.href = this.href;
33022 var cn = cfg.cn[0].cn;
33024 if(this.title.length){
33027 cls: 'roo-brick-title',
33032 if(this.html.length){
33035 cls: 'roo-brick-text',
33042 if(this.bgimage.length){
33045 cls: 'roo-brick-image-view',
33053 initEvents: function()
33055 if(this.title.length || this.html.length){
33056 this.el.on('mouseenter' ,this.enter, this);
33057 this.el.on('mouseleave', this.leave, this);
33060 Roo.EventManager.onWindowResize(this.resize, this);
33062 if(this.bgimage.length){
33063 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33064 this.imageEl.on('load', this.onImageLoad, this);
33071 onImageLoad : function()
33076 resize : function()
33078 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33080 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33082 if(this.bgimage.length){
33083 var image = this.el.select('.roo-brick-image-view', true).first();
33085 image.setWidth(paragraph.getWidth());
33088 image.setHeight(paragraph.getWidth());
33091 this.el.setHeight(image.getHeight());
33092 paragraph.setHeight(image.getHeight());
33098 enter: function(e, el)
33100 e.preventDefault();
33102 if(this.bgimage.length){
33103 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33104 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33108 leave: function(e, el)
33110 e.preventDefault();
33112 if(this.bgimage.length){
33113 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33114 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33129 * @class Roo.bootstrap.NumberField
33130 * @extends Roo.bootstrap.Input
33131 * Bootstrap NumberField class
33137 * Create a new NumberField
33138 * @param {Object} config The config object
33141 Roo.bootstrap.NumberField = function(config){
33142 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33145 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33148 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33150 allowDecimals : true,
33152 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33154 decimalSeparator : ".",
33156 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33158 decimalPrecision : 2,
33160 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33162 allowNegative : true,
33165 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33169 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33171 minValue : Number.NEGATIVE_INFINITY,
33173 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33175 maxValue : Number.MAX_VALUE,
33177 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33179 minText : "The minimum value for this field is {0}",
33181 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33183 maxText : "The maximum value for this field is {0}",
33185 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33186 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33188 nanText : "{0} is not a valid number",
33190 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33194 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33196 thousandsDelimiter : false,
33198 * @cfg {String} valueAlign alignment of value
33200 valueAlign : "left",
33202 getAutoCreate : function()
33204 var hiddenInput = {
33208 cls: 'hidden-number-input'
33212 hiddenInput.name = this.name;
33217 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33219 this.name = hiddenInput.name;
33221 if(cfg.cn.length > 0) {
33222 cfg.cn.push(hiddenInput);
33229 initEvents : function()
33231 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33233 var allowed = "0123456789";
33235 if(this.allowDecimals){
33236 allowed += this.decimalSeparator;
33239 if(this.allowNegative){
33243 if(this.thousandsDelimiter) {
33247 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33249 var keyPress = function(e){
33251 var k = e.getKey();
33253 var c = e.getCharCode();
33256 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33257 allowed.indexOf(String.fromCharCode(c)) === -1
33263 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33267 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33272 this.el.on("keypress", keyPress, this);
33275 validateValue : function(value)
33278 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33282 var num = this.parseValue(value);
33285 this.markInvalid(String.format(this.nanText, value));
33289 if(num < this.minValue){
33290 this.markInvalid(String.format(this.minText, this.minValue));
33294 if(num > this.maxValue){
33295 this.markInvalid(String.format(this.maxText, this.maxValue));
33302 getValue : function()
33304 var v = this.hiddenEl().getValue();
33306 return this.fixPrecision(this.parseValue(v));
33309 parseValue : function(value)
33311 if(this.thousandsDelimiter) {
33313 r = new RegExp(",", "g");
33314 value = value.replace(r, "");
33317 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33318 return isNaN(value) ? '' : value;
33321 fixPrecision : function(value)
33323 if(this.thousandsDelimiter) {
33325 r = new RegExp(",", "g");
33326 value = value.replace(r, "");
33329 var nan = isNaN(value);
33331 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33332 return nan ? '' : value;
33334 return parseFloat(value).toFixed(this.decimalPrecision);
33337 setValue : function(v)
33339 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33345 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33347 this.inputEl().dom.value = (v == '') ? '' :
33348 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33350 if(!this.allowZero && v === '0') {
33351 this.hiddenEl().dom.value = '';
33352 this.inputEl().dom.value = '';
33359 decimalPrecisionFcn : function(v)
33361 return Math.floor(v);
33364 beforeBlur : function()
33370 var v = this.parseValue(this.getRawValue());
33377 hiddenEl : function()
33379 return this.el.select('input.hidden-number-input',true).first();
33391 * @class Roo.bootstrap.DocumentSlider
33392 * @extends Roo.bootstrap.Component
33393 * Bootstrap DocumentSlider class
33396 * Create a new DocumentViewer
33397 * @param {Object} config The config object
33400 Roo.bootstrap.DocumentSlider = function(config){
33401 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33408 * Fire after initEvent
33409 * @param {Roo.bootstrap.DocumentSlider} this
33414 * Fire after update
33415 * @param {Roo.bootstrap.DocumentSlider} this
33421 * @param {Roo.bootstrap.DocumentSlider} this
33427 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33433 getAutoCreate : function()
33437 cls : 'roo-document-slider',
33441 cls : 'roo-document-slider-header',
33445 cls : 'roo-document-slider-header-title'
33451 cls : 'roo-document-slider-body',
33455 cls : 'roo-document-slider-prev',
33459 cls : 'fa fa-chevron-left'
33465 cls : 'roo-document-slider-thumb',
33469 cls : 'roo-document-slider-image'
33475 cls : 'roo-document-slider-next',
33479 cls : 'fa fa-chevron-right'
33491 initEvents : function()
33493 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33494 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33496 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33497 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33499 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33500 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33502 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33503 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33505 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33506 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33508 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33509 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33511 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33512 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33514 this.thumbEl.on('click', this.onClick, this);
33516 this.prevIndicator.on('click', this.prev, this);
33518 this.nextIndicator.on('click', this.next, this);
33522 initial : function()
33524 if(this.files.length){
33525 this.indicator = 1;
33529 this.fireEvent('initial', this);
33532 update : function()
33534 this.imageEl.attr('src', this.files[this.indicator - 1]);
33536 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33538 this.prevIndicator.show();
33540 if(this.indicator == 1){
33541 this.prevIndicator.hide();
33544 this.nextIndicator.show();
33546 if(this.indicator == this.files.length){
33547 this.nextIndicator.hide();
33550 this.thumbEl.scrollTo('top');
33552 this.fireEvent('update', this);
33555 onClick : function(e)
33557 e.preventDefault();
33559 this.fireEvent('click', this);
33564 e.preventDefault();
33566 this.indicator = Math.max(1, this.indicator - 1);
33573 e.preventDefault();
33575 this.indicator = Math.min(this.files.length, this.indicator + 1);
33589 * @class Roo.bootstrap.RadioSet
33590 * @extends Roo.bootstrap.Input
33591 * Bootstrap RadioSet class
33592 * @cfg {String} indicatorpos (left|right) default left
33593 * @cfg {Boolean} inline (true|false) inline the element (default true)
33594 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33596 * Create a new RadioSet
33597 * @param {Object} config The config object
33600 Roo.bootstrap.RadioSet = function(config){
33602 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33606 Roo.bootstrap.RadioSet.register(this);
33611 * Fires when the element is checked or unchecked.
33612 * @param {Roo.bootstrap.RadioSet} this This radio
33613 * @param {Roo.bootstrap.Radio} item The checked item
33618 * Fires when the element is click.
33619 * @param {Roo.bootstrap.RadioSet} this This radio set
33620 * @param {Roo.bootstrap.Radio} item The checked item
33621 * @param {Roo.EventObject} e The event object
33628 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33636 indicatorpos : 'left',
33638 getAutoCreate : function()
33642 cls : 'roo-radio-set-label',
33646 html : this.fieldLabel
33651 if(this.indicatorpos == 'left'){
33654 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33655 tooltip : 'This field is required'
33660 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33661 tooltip : 'This field is required'
33667 cls : 'roo-radio-set-items'
33670 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33672 if (align === 'left' && this.fieldLabel.length) {
33675 cls : "roo-radio-set-right",
33681 if(this.labelWidth > 12){
33682 label.style = "width: " + this.labelWidth + 'px';
33685 if(this.labelWidth < 13 && this.labelmd == 0){
33686 this.labelmd = this.labelWidth;
33689 if(this.labellg > 0){
33690 label.cls += ' col-lg-' + this.labellg;
33691 items.cls += ' col-lg-' + (12 - this.labellg);
33694 if(this.labelmd > 0){
33695 label.cls += ' col-md-' + this.labelmd;
33696 items.cls += ' col-md-' + (12 - this.labelmd);
33699 if(this.labelsm > 0){
33700 label.cls += ' col-sm-' + this.labelsm;
33701 items.cls += ' col-sm-' + (12 - this.labelsm);
33704 if(this.labelxs > 0){
33705 label.cls += ' col-xs-' + this.labelxs;
33706 items.cls += ' col-xs-' + (12 - this.labelxs);
33712 cls : 'roo-radio-set',
33716 cls : 'roo-radio-set-input',
33719 value : this.value ? this.value : ''
33726 if(this.weight.length){
33727 cfg.cls += ' roo-radio-' + this.weight;
33731 cfg.cls += ' roo-radio-set-inline';
33735 ['xs','sm','md','lg'].map(function(size){
33736 if (settings[size]) {
33737 cfg.cls += ' col-' + size + '-' + settings[size];
33745 initEvents : function()
33747 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33748 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33750 if(!this.fieldLabel.length){
33751 this.labelEl.hide();
33754 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33755 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33757 this.indicator = this.indicatorEl();
33759 if(this.indicator){
33760 this.indicator.addClass('invisible');
33763 this.originalValue = this.getValue();
33767 inputEl: function ()
33769 return this.el.select('.roo-radio-set-input', true).first();
33772 getChildContainer : function()
33774 return this.itemsEl;
33777 register : function(item)
33779 this.radioes.push(item);
33783 validate : function()
33785 if(this.getVisibilityEl().hasClass('hidden')){
33791 Roo.each(this.radioes, function(i){
33800 if(this.allowBlank) {
33804 if(this.disabled || valid){
33809 this.markInvalid();
33814 markValid : function()
33816 if(this.labelEl.isVisible(true)){
33817 this.indicatorEl().removeClass('visible');
33818 this.indicatorEl().addClass('invisible');
33821 this.el.removeClass([this.invalidClass, this.validClass]);
33822 this.el.addClass(this.validClass);
33824 this.fireEvent('valid', this);
33827 markInvalid : function(msg)
33829 if(this.allowBlank || this.disabled){
33833 if(this.labelEl.isVisible(true)){
33834 this.indicatorEl().removeClass('invisible');
33835 this.indicatorEl().addClass('visible');
33838 this.el.removeClass([this.invalidClass, this.validClass]);
33839 this.el.addClass(this.invalidClass);
33841 this.fireEvent('invalid', this, msg);
33845 setValue : function(v, suppressEvent)
33847 if(this.value === v){
33854 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33857 Roo.each(this.radioes, function(i){
33859 i.el.removeClass('checked');
33862 Roo.each(this.radioes, function(i){
33864 if(i.value === v || i.value.toString() === v.toString()){
33866 i.el.addClass('checked');
33868 if(suppressEvent !== true){
33869 this.fireEvent('check', this, i);
33880 clearInvalid : function(){
33882 if(!this.el || this.preventMark){
33886 this.el.removeClass([this.invalidClass]);
33888 this.fireEvent('valid', this);
33893 Roo.apply(Roo.bootstrap.RadioSet, {
33897 register : function(set)
33899 this.groups[set.name] = set;
33902 get: function(name)
33904 if (typeof(this.groups[name]) == 'undefined') {
33908 return this.groups[name] ;
33914 * Ext JS Library 1.1.1
33915 * Copyright(c) 2006-2007, Ext JS, LLC.
33917 * Originally Released Under LGPL - original licence link has changed is not relivant.
33920 * <script type="text/javascript">
33925 * @class Roo.bootstrap.SplitBar
33926 * @extends Roo.util.Observable
33927 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33931 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33932 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33933 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33934 split.minSize = 100;
33935 split.maxSize = 600;
33936 split.animate = true;
33937 split.on('moved', splitterMoved);
33940 * Create a new SplitBar
33941 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33942 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33943 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33944 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33945 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33946 position of the SplitBar).
33948 Roo.bootstrap.SplitBar = function(cfg){
33953 // dragElement : elm
33954 // resizingElement: el,
33956 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33957 // placement : Roo.bootstrap.SplitBar.LEFT ,
33958 // existingProxy ???
33961 this.el = Roo.get(cfg.dragElement, true);
33962 this.el.dom.unselectable = "on";
33964 this.resizingEl = Roo.get(cfg.resizingElement, true);
33968 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33969 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33972 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33975 * The minimum size of the resizing element. (Defaults to 0)
33981 * The maximum size of the resizing element. (Defaults to 2000)
33984 this.maxSize = 2000;
33987 * Whether to animate the transition to the new size
33990 this.animate = false;
33993 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33996 this.useShim = false;
34001 if(!cfg.existingProxy){
34003 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34005 this.proxy = Roo.get(cfg.existingProxy).dom;
34008 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34011 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34014 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34017 this.dragSpecs = {};
34020 * @private The adapter to use to positon and resize elements
34022 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34023 this.adapter.init(this);
34025 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34027 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34028 this.el.addClass("roo-splitbar-h");
34031 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34032 this.el.addClass("roo-splitbar-v");
34038 * Fires when the splitter is moved (alias for {@link #event-moved})
34039 * @param {Roo.bootstrap.SplitBar} this
34040 * @param {Number} newSize the new width or height
34045 * Fires when the splitter is moved
34046 * @param {Roo.bootstrap.SplitBar} this
34047 * @param {Number} newSize the new width or height
34051 * @event beforeresize
34052 * Fires before the splitter is dragged
34053 * @param {Roo.bootstrap.SplitBar} this
34055 "beforeresize" : true,
34057 "beforeapply" : true
34060 Roo.util.Observable.call(this);
34063 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34064 onStartProxyDrag : function(x, y){
34065 this.fireEvent("beforeresize", this);
34067 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34069 o.enableDisplayMode("block");
34070 // all splitbars share the same overlay
34071 Roo.bootstrap.SplitBar.prototype.overlay = o;
34073 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34074 this.overlay.show();
34075 Roo.get(this.proxy).setDisplayed("block");
34076 var size = this.adapter.getElementSize(this);
34077 this.activeMinSize = this.getMinimumSize();;
34078 this.activeMaxSize = this.getMaximumSize();;
34079 var c1 = size - this.activeMinSize;
34080 var c2 = Math.max(this.activeMaxSize - size, 0);
34081 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34082 this.dd.resetConstraints();
34083 this.dd.setXConstraint(
34084 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34085 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34087 this.dd.setYConstraint(0, 0);
34089 this.dd.resetConstraints();
34090 this.dd.setXConstraint(0, 0);
34091 this.dd.setYConstraint(
34092 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34093 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34096 this.dragSpecs.startSize = size;
34097 this.dragSpecs.startPoint = [x, y];
34098 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34102 * @private Called after the drag operation by the DDProxy
34104 onEndProxyDrag : function(e){
34105 Roo.get(this.proxy).setDisplayed(false);
34106 var endPoint = Roo.lib.Event.getXY(e);
34108 this.overlay.hide();
34111 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34112 newSize = this.dragSpecs.startSize +
34113 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34114 endPoint[0] - this.dragSpecs.startPoint[0] :
34115 this.dragSpecs.startPoint[0] - endPoint[0]
34118 newSize = this.dragSpecs.startSize +
34119 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34120 endPoint[1] - this.dragSpecs.startPoint[1] :
34121 this.dragSpecs.startPoint[1] - endPoint[1]
34124 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34125 if(newSize != this.dragSpecs.startSize){
34126 if(this.fireEvent('beforeapply', this, newSize) !== false){
34127 this.adapter.setElementSize(this, newSize);
34128 this.fireEvent("moved", this, newSize);
34129 this.fireEvent("resize", this, newSize);
34135 * Get the adapter this SplitBar uses
34136 * @return The adapter object
34138 getAdapter : function(){
34139 return this.adapter;
34143 * Set the adapter this SplitBar uses
34144 * @param {Object} adapter A SplitBar adapter object
34146 setAdapter : function(adapter){
34147 this.adapter = adapter;
34148 this.adapter.init(this);
34152 * Gets the minimum size for the resizing element
34153 * @return {Number} The minimum size
34155 getMinimumSize : function(){
34156 return this.minSize;
34160 * Sets the minimum size for the resizing element
34161 * @param {Number} minSize The minimum size
34163 setMinimumSize : function(minSize){
34164 this.minSize = minSize;
34168 * Gets the maximum size for the resizing element
34169 * @return {Number} The maximum size
34171 getMaximumSize : function(){
34172 return this.maxSize;
34176 * Sets the maximum size for the resizing element
34177 * @param {Number} maxSize The maximum size
34179 setMaximumSize : function(maxSize){
34180 this.maxSize = maxSize;
34184 * Sets the initialize size for the resizing element
34185 * @param {Number} size The initial size
34187 setCurrentSize : function(size){
34188 var oldAnimate = this.animate;
34189 this.animate = false;
34190 this.adapter.setElementSize(this, size);
34191 this.animate = oldAnimate;
34195 * Destroy this splitbar.
34196 * @param {Boolean} removeEl True to remove the element
34198 destroy : function(removeEl){
34200 this.shim.remove();
34203 this.proxy.parentNode.removeChild(this.proxy);
34211 * @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.
34213 Roo.bootstrap.SplitBar.createProxy = function(dir){
34214 var proxy = new Roo.Element(document.createElement("div"));
34215 proxy.unselectable();
34216 var cls = 'roo-splitbar-proxy';
34217 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34218 document.body.appendChild(proxy.dom);
34223 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34224 * Default Adapter. It assumes the splitter and resizing element are not positioned
34225 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34227 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34230 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34231 // do nothing for now
34232 init : function(s){
34236 * Called before drag operations to get the current size of the resizing element.
34237 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34239 getElementSize : function(s){
34240 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34241 return s.resizingEl.getWidth();
34243 return s.resizingEl.getHeight();
34248 * Called after drag operations to set the size of the resizing element.
34249 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34250 * @param {Number} newSize The new size to set
34251 * @param {Function} onComplete A function to be invoked when resizing is complete
34253 setElementSize : function(s, newSize, onComplete){
34254 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34256 s.resizingEl.setWidth(newSize);
34258 onComplete(s, newSize);
34261 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34266 s.resizingEl.setHeight(newSize);
34268 onComplete(s, newSize);
34271 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34278 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34279 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34280 * Adapter that moves the splitter element to align with the resized sizing element.
34281 * Used with an absolute positioned SplitBar.
34282 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34283 * document.body, make sure you assign an id to the body element.
34285 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34286 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34287 this.container = Roo.get(container);
34290 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34291 init : function(s){
34292 this.basic.init(s);
34295 getElementSize : function(s){
34296 return this.basic.getElementSize(s);
34299 setElementSize : function(s, newSize, onComplete){
34300 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34303 moveSplitter : function(s){
34304 var yes = Roo.bootstrap.SplitBar;
34305 switch(s.placement){
34307 s.el.setX(s.resizingEl.getRight());
34310 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34313 s.el.setY(s.resizingEl.getBottom());
34316 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34323 * Orientation constant - Create a vertical SplitBar
34327 Roo.bootstrap.SplitBar.VERTICAL = 1;
34330 * Orientation constant - Create a horizontal SplitBar
34334 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34337 * Placement constant - The resizing element is to the left of the splitter element
34341 Roo.bootstrap.SplitBar.LEFT = 1;
34344 * Placement constant - The resizing element is to the right of the splitter element
34348 Roo.bootstrap.SplitBar.RIGHT = 2;
34351 * Placement constant - The resizing element is positioned above the splitter element
34355 Roo.bootstrap.SplitBar.TOP = 3;
34358 * Placement constant - The resizing element is positioned under splitter element
34362 Roo.bootstrap.SplitBar.BOTTOM = 4;
34363 Roo.namespace("Roo.bootstrap.layout");/*
34365 * Ext JS Library 1.1.1
34366 * Copyright(c) 2006-2007, Ext JS, LLC.
34368 * Originally Released Under LGPL - original licence link has changed is not relivant.
34371 * <script type="text/javascript">
34375 * @class Roo.bootstrap.layout.Manager
34376 * @extends Roo.bootstrap.Component
34377 * Base class for layout managers.
34379 Roo.bootstrap.layout.Manager = function(config)
34381 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34387 /** false to disable window resize monitoring @type Boolean */
34388 this.monitorWindowResize = true;
34393 * Fires when a layout is performed.
34394 * @param {Roo.LayoutManager} this
34398 * @event regionresized
34399 * Fires when the user resizes a region.
34400 * @param {Roo.LayoutRegion} region The resized region
34401 * @param {Number} newSize The new size (width for east/west, height for north/south)
34403 "regionresized" : true,
34405 * @event regioncollapsed
34406 * Fires when a region is collapsed.
34407 * @param {Roo.LayoutRegion} region The collapsed region
34409 "regioncollapsed" : true,
34411 * @event regionexpanded
34412 * Fires when a region is expanded.
34413 * @param {Roo.LayoutRegion} region The expanded region
34415 "regionexpanded" : true
34417 this.updating = false;
34420 this.el = Roo.get(config.el);
34426 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34431 monitorWindowResize : true,
34437 onRender : function(ct, position)
34440 this.el = Roo.get(ct);
34443 //this.fireEvent('render',this);
34447 initEvents: function()
34451 // ie scrollbar fix
34452 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34453 document.body.scroll = "no";
34454 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34455 this.el.position('relative');
34457 this.id = this.el.id;
34458 this.el.addClass("roo-layout-container");
34459 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34460 if(this.el.dom != document.body ) {
34461 this.el.on('resize', this.layout,this);
34462 this.el.on('show', this.layout,this);
34468 * Returns true if this layout is currently being updated
34469 * @return {Boolean}
34471 isUpdating : function(){
34472 return this.updating;
34476 * Suspend the LayoutManager from doing auto-layouts while
34477 * making multiple add or remove calls
34479 beginUpdate : function(){
34480 this.updating = true;
34484 * Restore auto-layouts and optionally disable the manager from performing a layout
34485 * @param {Boolean} noLayout true to disable a layout update
34487 endUpdate : function(noLayout){
34488 this.updating = false;
34494 layout: function(){
34498 onRegionResized : function(region, newSize){
34499 this.fireEvent("regionresized", region, newSize);
34503 onRegionCollapsed : function(region){
34504 this.fireEvent("regioncollapsed", region);
34507 onRegionExpanded : function(region){
34508 this.fireEvent("regionexpanded", region);
34512 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34513 * performs box-model adjustments.
34514 * @return {Object} The size as an object {width: (the width), height: (the height)}
34516 getViewSize : function()
34519 if(this.el.dom != document.body){
34520 size = this.el.getSize();
34522 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34524 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34525 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34530 * Returns the Element this layout is bound to.
34531 * @return {Roo.Element}
34533 getEl : function(){
34538 * Returns the specified region.
34539 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34540 * @return {Roo.LayoutRegion}
34542 getRegion : function(target){
34543 return this.regions[target.toLowerCase()];
34546 onWindowResize : function(){
34547 if(this.monitorWindowResize){
34554 * Ext JS Library 1.1.1
34555 * Copyright(c) 2006-2007, Ext JS, LLC.
34557 * Originally Released Under LGPL - original licence link has changed is not relivant.
34560 * <script type="text/javascript">
34563 * @class Roo.bootstrap.layout.Border
34564 * @extends Roo.bootstrap.layout.Manager
34565 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34566 * please see: examples/bootstrap/nested.html<br><br>
34568 <b>The container the layout is rendered into can be either the body element or any other element.
34569 If it is not the body element, the container needs to either be an absolute positioned element,
34570 or you will need to add "position:relative" to the css of the container. You will also need to specify
34571 the container size if it is not the body element.</b>
34574 * Create a new Border
34575 * @param {Object} config Configuration options
34577 Roo.bootstrap.layout.Border = function(config){
34578 config = config || {};
34579 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34583 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34584 if(config[region]){
34585 config[region].region = region;
34586 this.addRegion(config[region]);
34592 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34594 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34596 * Creates and adds a new region if it doesn't already exist.
34597 * @param {String} target The target region key (north, south, east, west or center).
34598 * @param {Object} config The regions config object
34599 * @return {BorderLayoutRegion} The new region
34601 addRegion : function(config)
34603 if(!this.regions[config.region]){
34604 var r = this.factory(config);
34605 this.bindRegion(r);
34607 return this.regions[config.region];
34611 bindRegion : function(r){
34612 this.regions[r.config.region] = r;
34614 r.on("visibilitychange", this.layout, this);
34615 r.on("paneladded", this.layout, this);
34616 r.on("panelremoved", this.layout, this);
34617 r.on("invalidated", this.layout, this);
34618 r.on("resized", this.onRegionResized, this);
34619 r.on("collapsed", this.onRegionCollapsed, this);
34620 r.on("expanded", this.onRegionExpanded, this);
34624 * Performs a layout update.
34626 layout : function()
34628 if(this.updating) {
34632 // render all the rebions if they have not been done alreayd?
34633 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34634 if(this.regions[region] && !this.regions[region].bodyEl){
34635 this.regions[region].onRender(this.el)
34639 var size = this.getViewSize();
34640 var w = size.width;
34641 var h = size.height;
34646 //var x = 0, y = 0;
34648 var rs = this.regions;
34649 var north = rs["north"];
34650 var south = rs["south"];
34651 var west = rs["west"];
34652 var east = rs["east"];
34653 var center = rs["center"];
34654 //if(this.hideOnLayout){ // not supported anymore
34655 //c.el.setStyle("display", "none");
34657 if(north && north.isVisible()){
34658 var b = north.getBox();
34659 var m = north.getMargins();
34660 b.width = w - (m.left+m.right);
34663 centerY = b.height + b.y + m.bottom;
34664 centerH -= centerY;
34665 north.updateBox(this.safeBox(b));
34667 if(south && south.isVisible()){
34668 var b = south.getBox();
34669 var m = south.getMargins();
34670 b.width = w - (m.left+m.right);
34672 var totalHeight = (b.height + m.top + m.bottom);
34673 b.y = h - totalHeight + m.top;
34674 centerH -= totalHeight;
34675 south.updateBox(this.safeBox(b));
34677 if(west && west.isVisible()){
34678 var b = west.getBox();
34679 var m = west.getMargins();
34680 b.height = centerH - (m.top+m.bottom);
34682 b.y = centerY + m.top;
34683 var totalWidth = (b.width + m.left + m.right);
34684 centerX += totalWidth;
34685 centerW -= totalWidth;
34686 west.updateBox(this.safeBox(b));
34688 if(east && east.isVisible()){
34689 var b = east.getBox();
34690 var m = east.getMargins();
34691 b.height = centerH - (m.top+m.bottom);
34692 var totalWidth = (b.width + m.left + m.right);
34693 b.x = w - totalWidth + m.left;
34694 b.y = centerY + m.top;
34695 centerW -= totalWidth;
34696 east.updateBox(this.safeBox(b));
34699 var m = center.getMargins();
34701 x: centerX + m.left,
34702 y: centerY + m.top,
34703 width: centerW - (m.left+m.right),
34704 height: centerH - (m.top+m.bottom)
34706 //if(this.hideOnLayout){
34707 //center.el.setStyle("display", "block");
34709 center.updateBox(this.safeBox(centerBox));
34712 this.fireEvent("layout", this);
34716 safeBox : function(box){
34717 box.width = Math.max(0, box.width);
34718 box.height = Math.max(0, box.height);
34723 * Adds a ContentPanel (or subclass) to this layout.
34724 * @param {String} target The target region key (north, south, east, west or center).
34725 * @param {Roo.ContentPanel} panel The panel to add
34726 * @return {Roo.ContentPanel} The added panel
34728 add : function(target, panel){
34730 target = target.toLowerCase();
34731 return this.regions[target].add(panel);
34735 * Remove a ContentPanel (or subclass) to this layout.
34736 * @param {String} target The target region key (north, south, east, west or center).
34737 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34738 * @return {Roo.ContentPanel} The removed panel
34740 remove : function(target, panel){
34741 target = target.toLowerCase();
34742 return this.regions[target].remove(panel);
34746 * Searches all regions for a panel with the specified id
34747 * @param {String} panelId
34748 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34750 findPanel : function(panelId){
34751 var rs = this.regions;
34752 for(var target in rs){
34753 if(typeof rs[target] != "function"){
34754 var p = rs[target].getPanel(panelId);
34764 * Searches all regions for a panel with the specified id and activates (shows) it.
34765 * @param {String/ContentPanel} panelId The panels id or the panel itself
34766 * @return {Roo.ContentPanel} The shown panel or null
34768 showPanel : function(panelId) {
34769 var rs = this.regions;
34770 for(var target in rs){
34771 var r = rs[target];
34772 if(typeof r != "function"){
34773 if(r.hasPanel(panelId)){
34774 return r.showPanel(panelId);
34782 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34783 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34786 restoreState : function(provider){
34788 provider = Roo.state.Manager;
34790 var sm = new Roo.LayoutStateManager();
34791 sm.init(this, provider);
34797 * Adds a xtype elements to the layout.
34801 xtype : 'ContentPanel',
34808 xtype : 'NestedLayoutPanel',
34814 items : [ ... list of content panels or nested layout panels.. ]
34818 * @param {Object} cfg Xtype definition of item to add.
34820 addxtype : function(cfg)
34822 // basically accepts a pannel...
34823 // can accept a layout region..!?!?
34824 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34827 // theory? children can only be panels??
34829 //if (!cfg.xtype.match(/Panel$/)) {
34834 if (typeof(cfg.region) == 'undefined') {
34835 Roo.log("Failed to add Panel, region was not set");
34839 var region = cfg.region;
34845 xitems = cfg.items;
34852 case 'Content': // ContentPanel (el, cfg)
34853 case 'Scroll': // ContentPanel (el, cfg)
34855 cfg.autoCreate = true;
34856 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34858 // var el = this.el.createChild();
34859 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34862 this.add(region, ret);
34866 case 'TreePanel': // our new panel!
34867 cfg.el = this.el.createChild();
34868 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34869 this.add(region, ret);
34874 // create a new Layout (which is a Border Layout...
34876 var clayout = cfg.layout;
34877 clayout.el = this.el.createChild();
34878 clayout.items = clayout.items || [];
34882 // replace this exitems with the clayout ones..
34883 xitems = clayout.items;
34885 // force background off if it's in center...
34886 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34887 cfg.background = false;
34889 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34892 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34893 //console.log('adding nested layout panel ' + cfg.toSource());
34894 this.add(region, ret);
34895 nb = {}; /// find first...
34900 // needs grid and region
34902 //var el = this.getRegion(region).el.createChild();
34904 *var el = this.el.createChild();
34905 // create the grid first...
34906 cfg.grid.container = el;
34907 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34910 if (region == 'center' && this.active ) {
34911 cfg.background = false;
34914 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34916 this.add(region, ret);
34918 if (cfg.background) {
34919 // render grid on panel activation (if panel background)
34920 ret.on('activate', function(gp) {
34921 if (!gp.grid.rendered) {
34922 // gp.grid.render(el);
34926 // cfg.grid.render(el);
34932 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34933 // it was the old xcomponent building that caused this before.
34934 // espeically if border is the top element in the tree.
34944 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34946 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34947 this.add(region, ret);
34951 throw "Can not add '" + cfg.xtype + "' to Border";
34957 this.beginUpdate();
34961 Roo.each(xitems, function(i) {
34962 region = nb && i.region ? i.region : false;
34964 var add = ret.addxtype(i);
34967 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34968 if (!i.background) {
34969 abn[region] = nb[region] ;
34976 // make the last non-background panel active..
34977 //if (nb) { Roo.log(abn); }
34980 for(var r in abn) {
34981 region = this.getRegion(r);
34983 // tried using nb[r], but it does not work..
34985 region.showPanel(abn[r]);
34996 factory : function(cfg)
34999 var validRegions = Roo.bootstrap.layout.Border.regions;
35001 var target = cfg.region;
35004 var r = Roo.bootstrap.layout;
35008 return new r.North(cfg);
35010 return new r.South(cfg);
35012 return new r.East(cfg);
35014 return new r.West(cfg);
35016 return new r.Center(cfg);
35018 throw 'Layout region "'+target+'" not supported.';
35025 * Ext JS Library 1.1.1
35026 * Copyright(c) 2006-2007, Ext JS, LLC.
35028 * Originally Released Under LGPL - original licence link has changed is not relivant.
35031 * <script type="text/javascript">
35035 * @class Roo.bootstrap.layout.Basic
35036 * @extends Roo.util.Observable
35037 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35038 * and does not have a titlebar, tabs or any other features. All it does is size and position
35039 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35040 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35041 * @cfg {string} region the region that it inhabits..
35042 * @cfg {bool} skipConfig skip config?
35046 Roo.bootstrap.layout.Basic = function(config){
35048 this.mgr = config.mgr;
35050 this.position = config.region;
35052 var skipConfig = config.skipConfig;
35056 * @scope Roo.BasicLayoutRegion
35060 * @event beforeremove
35061 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35062 * @param {Roo.LayoutRegion} this
35063 * @param {Roo.ContentPanel} panel The panel
35064 * @param {Object} e The cancel event object
35066 "beforeremove" : true,
35068 * @event invalidated
35069 * Fires when the layout for this region is changed.
35070 * @param {Roo.LayoutRegion} this
35072 "invalidated" : true,
35074 * @event visibilitychange
35075 * Fires when this region is shown or hidden
35076 * @param {Roo.LayoutRegion} this
35077 * @param {Boolean} visibility true or false
35079 "visibilitychange" : true,
35081 * @event paneladded
35082 * Fires when a panel is added.
35083 * @param {Roo.LayoutRegion} this
35084 * @param {Roo.ContentPanel} panel The panel
35086 "paneladded" : true,
35088 * @event panelremoved
35089 * Fires when a panel is removed.
35090 * @param {Roo.LayoutRegion} this
35091 * @param {Roo.ContentPanel} panel The panel
35093 "panelremoved" : true,
35095 * @event beforecollapse
35096 * Fires when this region before collapse.
35097 * @param {Roo.LayoutRegion} this
35099 "beforecollapse" : true,
35102 * Fires when this region is collapsed.
35103 * @param {Roo.LayoutRegion} this
35105 "collapsed" : true,
35108 * Fires when this region is expanded.
35109 * @param {Roo.LayoutRegion} this
35114 * Fires when this region is slid into view.
35115 * @param {Roo.LayoutRegion} this
35117 "slideshow" : true,
35120 * Fires when this region slides out of view.
35121 * @param {Roo.LayoutRegion} this
35123 "slidehide" : true,
35125 * @event panelactivated
35126 * Fires when a panel is activated.
35127 * @param {Roo.LayoutRegion} this
35128 * @param {Roo.ContentPanel} panel The activated panel
35130 "panelactivated" : true,
35133 * Fires when the user resizes this region.
35134 * @param {Roo.LayoutRegion} this
35135 * @param {Number} newSize The new size (width for east/west, height for north/south)
35139 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35140 this.panels = new Roo.util.MixedCollection();
35141 this.panels.getKey = this.getPanelId.createDelegate(this);
35143 this.activePanel = null;
35144 // ensure listeners are added...
35146 if (config.listeners || config.events) {
35147 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35148 listeners : config.listeners || {},
35149 events : config.events || {}
35153 if(skipConfig !== true){
35154 this.applyConfig(config);
35158 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35160 getPanelId : function(p){
35164 applyConfig : function(config){
35165 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35166 this.config = config;
35171 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35172 * the width, for horizontal (north, south) the height.
35173 * @param {Number} newSize The new width or height
35175 resizeTo : function(newSize){
35176 var el = this.el ? this.el :
35177 (this.activePanel ? this.activePanel.getEl() : null);
35179 switch(this.position){
35182 el.setWidth(newSize);
35183 this.fireEvent("resized", this, newSize);
35187 el.setHeight(newSize);
35188 this.fireEvent("resized", this, newSize);
35194 getBox : function(){
35195 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35198 getMargins : function(){
35199 return this.margins;
35202 updateBox : function(box){
35204 var el = this.activePanel.getEl();
35205 el.dom.style.left = box.x + "px";
35206 el.dom.style.top = box.y + "px";
35207 this.activePanel.setSize(box.width, box.height);
35211 * Returns the container element for this region.
35212 * @return {Roo.Element}
35214 getEl : function(){
35215 return this.activePanel;
35219 * Returns true if this region is currently visible.
35220 * @return {Boolean}
35222 isVisible : function(){
35223 return this.activePanel ? true : false;
35226 setActivePanel : function(panel){
35227 panel = this.getPanel(panel);
35228 if(this.activePanel && this.activePanel != panel){
35229 this.activePanel.setActiveState(false);
35230 this.activePanel.getEl().setLeftTop(-10000,-10000);
35232 this.activePanel = panel;
35233 panel.setActiveState(true);
35235 panel.setSize(this.box.width, this.box.height);
35237 this.fireEvent("panelactivated", this, panel);
35238 this.fireEvent("invalidated");
35242 * Show the specified panel.
35243 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35244 * @return {Roo.ContentPanel} The shown panel or null
35246 showPanel : function(panel){
35247 panel = this.getPanel(panel);
35249 this.setActivePanel(panel);
35255 * Get the active panel for this region.
35256 * @return {Roo.ContentPanel} The active panel or null
35258 getActivePanel : function(){
35259 return this.activePanel;
35263 * Add the passed ContentPanel(s)
35264 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35265 * @return {Roo.ContentPanel} The panel added (if only one was added)
35267 add : function(panel){
35268 if(arguments.length > 1){
35269 for(var i = 0, len = arguments.length; i < len; i++) {
35270 this.add(arguments[i]);
35274 if(this.hasPanel(panel)){
35275 this.showPanel(panel);
35278 var el = panel.getEl();
35279 if(el.dom.parentNode != this.mgr.el.dom){
35280 this.mgr.el.dom.appendChild(el.dom);
35282 if(panel.setRegion){
35283 panel.setRegion(this);
35285 this.panels.add(panel);
35286 el.setStyle("position", "absolute");
35287 if(!panel.background){
35288 this.setActivePanel(panel);
35289 if(this.config.initialSize && this.panels.getCount()==1){
35290 this.resizeTo(this.config.initialSize);
35293 this.fireEvent("paneladded", this, panel);
35298 * Returns true if the panel is in this region.
35299 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35300 * @return {Boolean}
35302 hasPanel : function(panel){
35303 if(typeof panel == "object"){ // must be panel obj
35304 panel = panel.getId();
35306 return this.getPanel(panel) ? true : false;
35310 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35311 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35312 * @param {Boolean} preservePanel Overrides the config preservePanel option
35313 * @return {Roo.ContentPanel} The panel that was removed
35315 remove : function(panel, preservePanel){
35316 panel = this.getPanel(panel);
35321 this.fireEvent("beforeremove", this, panel, e);
35322 if(e.cancel === true){
35325 var panelId = panel.getId();
35326 this.panels.removeKey(panelId);
35331 * Returns the panel specified or null if it's not in this region.
35332 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35333 * @return {Roo.ContentPanel}
35335 getPanel : function(id){
35336 if(typeof id == "object"){ // must be panel obj
35339 return this.panels.get(id);
35343 * Returns this regions position (north/south/east/west/center).
35346 getPosition: function(){
35347 return this.position;
35351 * Ext JS Library 1.1.1
35352 * Copyright(c) 2006-2007, Ext JS, LLC.
35354 * Originally Released Under LGPL - original licence link has changed is not relivant.
35357 * <script type="text/javascript">
35361 * @class Roo.bootstrap.layout.Region
35362 * @extends Roo.bootstrap.layout.Basic
35363 * This class represents a region in a layout manager.
35365 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35366 * @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})
35367 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35368 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35369 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35370 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35371 * @cfg {String} title The title for the region (overrides panel titles)
35372 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35373 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35374 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35375 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35376 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35377 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35378 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35379 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35380 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35381 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35383 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35384 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35385 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35386 * @cfg {Number} width For East/West panels
35387 * @cfg {Number} height For North/South panels
35388 * @cfg {Boolean} split To show the splitter
35389 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35391 * @cfg {string} cls Extra CSS classes to add to region
35393 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35394 * @cfg {string} region the region that it inhabits..
35397 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35398 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35400 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35401 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35402 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35404 Roo.bootstrap.layout.Region = function(config)
35406 this.applyConfig(config);
35408 var mgr = config.mgr;
35409 var pos = config.region;
35410 config.skipConfig = true;
35411 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35414 this.onRender(mgr.el);
35417 this.visible = true;
35418 this.collapsed = false;
35419 this.unrendered_panels = [];
35422 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35424 position: '', // set by wrapper (eg. north/south etc..)
35425 unrendered_panels : null, // unrendered panels.
35426 createBody : function(){
35427 /** This region's body element
35428 * @type Roo.Element */
35429 this.bodyEl = this.el.createChild({
35431 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35435 onRender: function(ctr, pos)
35437 var dh = Roo.DomHelper;
35438 /** This region's container element
35439 * @type Roo.Element */
35440 this.el = dh.append(ctr.dom, {
35442 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35444 /** This region's title element
35445 * @type Roo.Element */
35447 this.titleEl = dh.append(this.el.dom,
35450 unselectable: "on",
35451 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35453 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35454 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35457 this.titleEl.enableDisplayMode();
35458 /** This region's title text element
35459 * @type HTMLElement */
35460 this.titleTextEl = this.titleEl.dom.firstChild;
35461 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35463 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35464 this.closeBtn.enableDisplayMode();
35465 this.closeBtn.on("click", this.closeClicked, this);
35466 this.closeBtn.hide();
35468 this.createBody(this.config);
35469 if(this.config.hideWhenEmpty){
35471 this.on("paneladded", this.validateVisibility, this);
35472 this.on("panelremoved", this.validateVisibility, this);
35474 if(this.autoScroll){
35475 this.bodyEl.setStyle("overflow", "auto");
35477 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35479 //if(c.titlebar !== false){
35480 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35481 this.titleEl.hide();
35483 this.titleEl.show();
35484 if(this.config.title){
35485 this.titleTextEl.innerHTML = this.config.title;
35489 if(this.config.collapsed){
35490 this.collapse(true);
35492 if(this.config.hidden){
35496 if (this.unrendered_panels && this.unrendered_panels.length) {
35497 for (var i =0;i< this.unrendered_panels.length; i++) {
35498 this.add(this.unrendered_panels[i]);
35500 this.unrendered_panels = null;
35506 applyConfig : function(c)
35509 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35510 var dh = Roo.DomHelper;
35511 if(c.titlebar !== false){
35512 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35513 this.collapseBtn.on("click", this.collapse, this);
35514 this.collapseBtn.enableDisplayMode();
35516 if(c.showPin === true || this.showPin){
35517 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35518 this.stickBtn.enableDisplayMode();
35519 this.stickBtn.on("click", this.expand, this);
35520 this.stickBtn.hide();
35525 /** This region's collapsed element
35526 * @type Roo.Element */
35529 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35530 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35533 if(c.floatable !== false){
35534 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35535 this.collapsedEl.on("click", this.collapseClick, this);
35538 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35539 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35540 id: "message", unselectable: "on", style:{"float":"left"}});
35541 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35543 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35544 this.expandBtn.on("click", this.expand, this);
35548 if(this.collapseBtn){
35549 this.collapseBtn.setVisible(c.collapsible == true);
35552 this.cmargins = c.cmargins || this.cmargins ||
35553 (this.position == "west" || this.position == "east" ?
35554 {top: 0, left: 2, right:2, bottom: 0} :
35555 {top: 2, left: 0, right:0, bottom: 2});
35557 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35560 this.bottomTabs = c.tabPosition != "top";
35562 this.autoScroll = c.autoScroll || false;
35567 this.duration = c.duration || .30;
35568 this.slideDuration = c.slideDuration || .45;
35573 * Returns true if this region is currently visible.
35574 * @return {Boolean}
35576 isVisible : function(){
35577 return this.visible;
35581 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35582 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35584 //setCollapsedTitle : function(title){
35585 // title = title || " ";
35586 // if(this.collapsedTitleTextEl){
35587 // this.collapsedTitleTextEl.innerHTML = title;
35591 getBox : function(){
35593 // if(!this.collapsed){
35594 b = this.el.getBox(false, true);
35596 // b = this.collapsedEl.getBox(false, true);
35601 getMargins : function(){
35602 return this.margins;
35603 //return this.collapsed ? this.cmargins : this.margins;
35606 highlight : function(){
35607 this.el.addClass("x-layout-panel-dragover");
35610 unhighlight : function(){
35611 this.el.removeClass("x-layout-panel-dragover");
35614 updateBox : function(box)
35616 if (!this.bodyEl) {
35617 return; // not rendered yet..
35621 if(!this.collapsed){
35622 this.el.dom.style.left = box.x + "px";
35623 this.el.dom.style.top = box.y + "px";
35624 this.updateBody(box.width, box.height);
35626 this.collapsedEl.dom.style.left = box.x + "px";
35627 this.collapsedEl.dom.style.top = box.y + "px";
35628 this.collapsedEl.setSize(box.width, box.height);
35631 this.tabs.autoSizeTabs();
35635 updateBody : function(w, h)
35638 this.el.setWidth(w);
35639 w -= this.el.getBorderWidth("rl");
35640 if(this.config.adjustments){
35641 w += this.config.adjustments[0];
35644 if(h !== null && h > 0){
35645 this.el.setHeight(h);
35646 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35647 h -= this.el.getBorderWidth("tb");
35648 if(this.config.adjustments){
35649 h += this.config.adjustments[1];
35651 this.bodyEl.setHeight(h);
35653 h = this.tabs.syncHeight(h);
35656 if(this.panelSize){
35657 w = w !== null ? w : this.panelSize.width;
35658 h = h !== null ? h : this.panelSize.height;
35660 if(this.activePanel){
35661 var el = this.activePanel.getEl();
35662 w = w !== null ? w : el.getWidth();
35663 h = h !== null ? h : el.getHeight();
35664 this.panelSize = {width: w, height: h};
35665 this.activePanel.setSize(w, h);
35667 if(Roo.isIE && this.tabs){
35668 this.tabs.el.repaint();
35673 * Returns the container element for this region.
35674 * @return {Roo.Element}
35676 getEl : function(){
35681 * Hides this region.
35684 //if(!this.collapsed){
35685 this.el.dom.style.left = "-2000px";
35688 // this.collapsedEl.dom.style.left = "-2000px";
35689 // this.collapsedEl.hide();
35691 this.visible = false;
35692 this.fireEvent("visibilitychange", this, false);
35696 * Shows this region if it was previously hidden.
35699 //if(!this.collapsed){
35702 // this.collapsedEl.show();
35704 this.visible = true;
35705 this.fireEvent("visibilitychange", this, true);
35708 closeClicked : function(){
35709 if(this.activePanel){
35710 this.remove(this.activePanel);
35714 collapseClick : function(e){
35716 e.stopPropagation();
35719 e.stopPropagation();
35725 * Collapses this region.
35726 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35729 collapse : function(skipAnim, skipCheck = false){
35730 if(this.collapsed) {
35734 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35736 this.collapsed = true;
35738 this.split.el.hide();
35740 if(this.config.animate && skipAnim !== true){
35741 this.fireEvent("invalidated", this);
35742 this.animateCollapse();
35744 this.el.setLocation(-20000,-20000);
35746 this.collapsedEl.show();
35747 this.fireEvent("collapsed", this);
35748 this.fireEvent("invalidated", this);
35754 animateCollapse : function(){
35759 * Expands this region if it was previously collapsed.
35760 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35761 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35764 expand : function(e, skipAnim){
35766 e.stopPropagation();
35768 if(!this.collapsed || this.el.hasActiveFx()) {
35772 this.afterSlideIn();
35775 this.collapsed = false;
35776 if(this.config.animate && skipAnim !== true){
35777 this.animateExpand();
35781 this.split.el.show();
35783 this.collapsedEl.setLocation(-2000,-2000);
35784 this.collapsedEl.hide();
35785 this.fireEvent("invalidated", this);
35786 this.fireEvent("expanded", this);
35790 animateExpand : function(){
35794 initTabs : function()
35796 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35798 var ts = new Roo.bootstrap.panel.Tabs({
35799 el: this.bodyEl.dom,
35800 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35801 disableTooltips: this.config.disableTabTips,
35802 toolbar : this.config.toolbar
35805 if(this.config.hideTabs){
35806 ts.stripWrap.setDisplayed(false);
35809 ts.resizeTabs = this.config.resizeTabs === true;
35810 ts.minTabWidth = this.config.minTabWidth || 40;
35811 ts.maxTabWidth = this.config.maxTabWidth || 250;
35812 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35813 ts.monitorResize = false;
35814 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35815 ts.bodyEl.addClass('roo-layout-tabs-body');
35816 this.panels.each(this.initPanelAsTab, this);
35819 initPanelAsTab : function(panel){
35820 var ti = this.tabs.addTab(
35824 this.config.closeOnTab && panel.isClosable(),
35827 if(panel.tabTip !== undefined){
35828 ti.setTooltip(panel.tabTip);
35830 ti.on("activate", function(){
35831 this.setActivePanel(panel);
35834 if(this.config.closeOnTab){
35835 ti.on("beforeclose", function(t, e){
35837 this.remove(panel);
35841 panel.tabItem = ti;
35846 updatePanelTitle : function(panel, title)
35848 if(this.activePanel == panel){
35849 this.updateTitle(title);
35852 var ti = this.tabs.getTab(panel.getEl().id);
35854 if(panel.tabTip !== undefined){
35855 ti.setTooltip(panel.tabTip);
35860 updateTitle : function(title){
35861 if(this.titleTextEl && !this.config.title){
35862 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35866 setActivePanel : function(panel)
35868 panel = this.getPanel(panel);
35869 if(this.activePanel && this.activePanel != panel){
35870 if(this.activePanel.setActiveState(false) === false){
35874 this.activePanel = panel;
35875 panel.setActiveState(true);
35876 if(this.panelSize){
35877 panel.setSize(this.panelSize.width, this.panelSize.height);
35880 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35882 this.updateTitle(panel.getTitle());
35884 this.fireEvent("invalidated", this);
35886 this.fireEvent("panelactivated", this, panel);
35890 * Shows the specified panel.
35891 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35892 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35894 showPanel : function(panel)
35896 panel = this.getPanel(panel);
35899 var tab = this.tabs.getTab(panel.getEl().id);
35900 if(tab.isHidden()){
35901 this.tabs.unhideTab(tab.id);
35905 this.setActivePanel(panel);
35912 * Get the active panel for this region.
35913 * @return {Roo.ContentPanel} The active panel or null
35915 getActivePanel : function(){
35916 return this.activePanel;
35919 validateVisibility : function(){
35920 if(this.panels.getCount() < 1){
35921 this.updateTitle(" ");
35922 this.closeBtn.hide();
35925 if(!this.isVisible()){
35932 * Adds the passed ContentPanel(s) to this region.
35933 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35934 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35936 add : function(panel)
35938 if(arguments.length > 1){
35939 for(var i = 0, len = arguments.length; i < len; i++) {
35940 this.add(arguments[i]);
35945 // if we have not been rendered yet, then we can not really do much of this..
35946 if (!this.bodyEl) {
35947 this.unrendered_panels.push(panel);
35954 if(this.hasPanel(panel)){
35955 this.showPanel(panel);
35958 panel.setRegion(this);
35959 this.panels.add(panel);
35960 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35961 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35962 // and hide them... ???
35963 this.bodyEl.dom.appendChild(panel.getEl().dom);
35964 if(panel.background !== true){
35965 this.setActivePanel(panel);
35967 this.fireEvent("paneladded", this, panel);
35974 this.initPanelAsTab(panel);
35978 if(panel.background !== true){
35979 this.tabs.activate(panel.getEl().id);
35981 this.fireEvent("paneladded", this, panel);
35986 * Hides the tab for the specified panel.
35987 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35989 hidePanel : function(panel){
35990 if(this.tabs && (panel = this.getPanel(panel))){
35991 this.tabs.hideTab(panel.getEl().id);
35996 * Unhides the tab for a previously hidden panel.
35997 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35999 unhidePanel : function(panel){
36000 if(this.tabs && (panel = this.getPanel(panel))){
36001 this.tabs.unhideTab(panel.getEl().id);
36005 clearPanels : function(){
36006 while(this.panels.getCount() > 0){
36007 this.remove(this.panels.first());
36012 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36013 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36014 * @param {Boolean} preservePanel Overrides the config preservePanel option
36015 * @return {Roo.ContentPanel} The panel that was removed
36017 remove : function(panel, preservePanel)
36019 panel = this.getPanel(panel);
36024 this.fireEvent("beforeremove", this, panel, e);
36025 if(e.cancel === true){
36028 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36029 var panelId = panel.getId();
36030 this.panels.removeKey(panelId);
36032 document.body.appendChild(panel.getEl().dom);
36035 this.tabs.removeTab(panel.getEl().id);
36036 }else if (!preservePanel){
36037 this.bodyEl.dom.removeChild(panel.getEl().dom);
36039 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36040 var p = this.panels.first();
36041 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36042 tempEl.appendChild(p.getEl().dom);
36043 this.bodyEl.update("");
36044 this.bodyEl.dom.appendChild(p.getEl().dom);
36046 this.updateTitle(p.getTitle());
36048 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36049 this.setActivePanel(p);
36051 panel.setRegion(null);
36052 if(this.activePanel == panel){
36053 this.activePanel = null;
36055 if(this.config.autoDestroy !== false && preservePanel !== true){
36056 try{panel.destroy();}catch(e){}
36058 this.fireEvent("panelremoved", this, panel);
36063 * Returns the TabPanel component used by this region
36064 * @return {Roo.TabPanel}
36066 getTabs : function(){
36070 createTool : function(parentEl, className){
36071 var btn = Roo.DomHelper.append(parentEl, {
36073 cls: "x-layout-tools-button",
36076 cls: "roo-layout-tools-button-inner " + className,
36080 btn.addClassOnOver("roo-layout-tools-button-over");
36085 * Ext JS Library 1.1.1
36086 * Copyright(c) 2006-2007, Ext JS, LLC.
36088 * Originally Released Under LGPL - original licence link has changed is not relivant.
36091 * <script type="text/javascript">
36097 * @class Roo.SplitLayoutRegion
36098 * @extends Roo.LayoutRegion
36099 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36101 Roo.bootstrap.layout.Split = function(config){
36102 this.cursor = config.cursor;
36103 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36106 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36108 splitTip : "Drag to resize.",
36109 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36110 useSplitTips : false,
36112 applyConfig : function(config){
36113 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36116 onRender : function(ctr,pos) {
36118 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36119 if(!this.config.split){
36124 var splitEl = Roo.DomHelper.append(ctr.dom, {
36126 id: this.el.id + "-split",
36127 cls: "roo-layout-split roo-layout-split-"+this.position,
36130 /** The SplitBar for this region
36131 * @type Roo.SplitBar */
36132 // does not exist yet...
36133 Roo.log([this.position, this.orientation]);
36135 this.split = new Roo.bootstrap.SplitBar({
36136 dragElement : splitEl,
36137 resizingElement: this.el,
36138 orientation : this.orientation
36141 this.split.on("moved", this.onSplitMove, this);
36142 this.split.useShim = this.config.useShim === true;
36143 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36144 if(this.useSplitTips){
36145 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36147 //if(config.collapsible){
36148 // this.split.el.on("dblclick", this.collapse, this);
36151 if(typeof this.config.minSize != "undefined"){
36152 this.split.minSize = this.config.minSize;
36154 if(typeof this.config.maxSize != "undefined"){
36155 this.split.maxSize = this.config.maxSize;
36157 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36158 this.hideSplitter();
36163 getHMaxSize : function(){
36164 var cmax = this.config.maxSize || 10000;
36165 var center = this.mgr.getRegion("center");
36166 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36169 getVMaxSize : function(){
36170 var cmax = this.config.maxSize || 10000;
36171 var center = this.mgr.getRegion("center");
36172 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36175 onSplitMove : function(split, newSize){
36176 this.fireEvent("resized", this, newSize);
36180 * Returns the {@link Roo.SplitBar} for this region.
36181 * @return {Roo.SplitBar}
36183 getSplitBar : function(){
36188 this.hideSplitter();
36189 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36192 hideSplitter : function(){
36194 this.split.el.setLocation(-2000,-2000);
36195 this.split.el.hide();
36201 this.split.el.show();
36203 Roo.bootstrap.layout.Split.superclass.show.call(this);
36206 beforeSlide: function(){
36207 if(Roo.isGecko){// firefox overflow auto bug workaround
36208 this.bodyEl.clip();
36210 this.tabs.bodyEl.clip();
36212 if(this.activePanel){
36213 this.activePanel.getEl().clip();
36215 if(this.activePanel.beforeSlide){
36216 this.activePanel.beforeSlide();
36222 afterSlide : function(){
36223 if(Roo.isGecko){// firefox overflow auto bug workaround
36224 this.bodyEl.unclip();
36226 this.tabs.bodyEl.unclip();
36228 if(this.activePanel){
36229 this.activePanel.getEl().unclip();
36230 if(this.activePanel.afterSlide){
36231 this.activePanel.afterSlide();
36237 initAutoHide : function(){
36238 if(this.autoHide !== false){
36239 if(!this.autoHideHd){
36240 var st = new Roo.util.DelayedTask(this.slideIn, this);
36241 this.autoHideHd = {
36242 "mouseout": function(e){
36243 if(!e.within(this.el, true)){
36247 "mouseover" : function(e){
36253 this.el.on(this.autoHideHd);
36257 clearAutoHide : function(){
36258 if(this.autoHide !== false){
36259 this.el.un("mouseout", this.autoHideHd.mouseout);
36260 this.el.un("mouseover", this.autoHideHd.mouseover);
36264 clearMonitor : function(){
36265 Roo.get(document).un("click", this.slideInIf, this);
36268 // these names are backwards but not changed for compat
36269 slideOut : function(){
36270 if(this.isSlid || this.el.hasActiveFx()){
36273 this.isSlid = true;
36274 if(this.collapseBtn){
36275 this.collapseBtn.hide();
36277 this.closeBtnState = this.closeBtn.getStyle('display');
36278 this.closeBtn.hide();
36280 this.stickBtn.show();
36283 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36284 this.beforeSlide();
36285 this.el.setStyle("z-index", 10001);
36286 this.el.slideIn(this.getSlideAnchor(), {
36287 callback: function(){
36289 this.initAutoHide();
36290 Roo.get(document).on("click", this.slideInIf, this);
36291 this.fireEvent("slideshow", this);
36298 afterSlideIn : function(){
36299 this.clearAutoHide();
36300 this.isSlid = false;
36301 this.clearMonitor();
36302 this.el.setStyle("z-index", "");
36303 if(this.collapseBtn){
36304 this.collapseBtn.show();
36306 this.closeBtn.setStyle('display', this.closeBtnState);
36308 this.stickBtn.hide();
36310 this.fireEvent("slidehide", this);
36313 slideIn : function(cb){
36314 if(!this.isSlid || this.el.hasActiveFx()){
36318 this.isSlid = false;
36319 this.beforeSlide();
36320 this.el.slideOut(this.getSlideAnchor(), {
36321 callback: function(){
36322 this.el.setLeftTop(-10000, -10000);
36324 this.afterSlideIn();
36332 slideInIf : function(e){
36333 if(!e.within(this.el)){
36338 animateCollapse : function(){
36339 this.beforeSlide();
36340 this.el.setStyle("z-index", 20000);
36341 var anchor = this.getSlideAnchor();
36342 this.el.slideOut(anchor, {
36343 callback : function(){
36344 this.el.setStyle("z-index", "");
36345 this.collapsedEl.slideIn(anchor, {duration:.3});
36347 this.el.setLocation(-10000,-10000);
36349 this.fireEvent("collapsed", this);
36356 animateExpand : function(){
36357 this.beforeSlide();
36358 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36359 this.el.setStyle("z-index", 20000);
36360 this.collapsedEl.hide({
36363 this.el.slideIn(this.getSlideAnchor(), {
36364 callback : function(){
36365 this.el.setStyle("z-index", "");
36368 this.split.el.show();
36370 this.fireEvent("invalidated", this);
36371 this.fireEvent("expanded", this);
36399 getAnchor : function(){
36400 return this.anchors[this.position];
36403 getCollapseAnchor : function(){
36404 return this.canchors[this.position];
36407 getSlideAnchor : function(){
36408 return this.sanchors[this.position];
36411 getAlignAdj : function(){
36412 var cm = this.cmargins;
36413 switch(this.position){
36429 getExpandAdj : function(){
36430 var c = this.collapsedEl, cm = this.cmargins;
36431 switch(this.position){
36433 return [-(cm.right+c.getWidth()+cm.left), 0];
36436 return [cm.right+c.getWidth()+cm.left, 0];
36439 return [0, -(cm.top+cm.bottom+c.getHeight())];
36442 return [0, cm.top+cm.bottom+c.getHeight()];
36448 * Ext JS Library 1.1.1
36449 * Copyright(c) 2006-2007, Ext JS, LLC.
36451 * Originally Released Under LGPL - original licence link has changed is not relivant.
36454 * <script type="text/javascript">
36457 * These classes are private internal classes
36459 Roo.bootstrap.layout.Center = function(config){
36460 config.region = "center";
36461 Roo.bootstrap.layout.Region.call(this, config);
36462 this.visible = true;
36463 this.minWidth = config.minWidth || 20;
36464 this.minHeight = config.minHeight || 20;
36467 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36469 // center panel can't be hidden
36473 // center panel can't be hidden
36476 getMinWidth: function(){
36477 return this.minWidth;
36480 getMinHeight: function(){
36481 return this.minHeight;
36494 Roo.bootstrap.layout.North = function(config)
36496 config.region = 'north';
36497 config.cursor = 'n-resize';
36499 Roo.bootstrap.layout.Split.call(this, config);
36503 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36504 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36505 this.split.el.addClass("roo-layout-split-v");
36507 var size = config.initialSize || config.height;
36508 if(typeof size != "undefined"){
36509 this.el.setHeight(size);
36512 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36514 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36518 getBox : function(){
36519 if(this.collapsed){
36520 return this.collapsedEl.getBox();
36522 var box = this.el.getBox();
36524 box.height += this.split.el.getHeight();
36529 updateBox : function(box){
36530 if(this.split && !this.collapsed){
36531 box.height -= this.split.el.getHeight();
36532 this.split.el.setLeft(box.x);
36533 this.split.el.setTop(box.y+box.height);
36534 this.split.el.setWidth(box.width);
36536 if(this.collapsed){
36537 this.updateBody(box.width, null);
36539 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36547 Roo.bootstrap.layout.South = function(config){
36548 config.region = 'south';
36549 config.cursor = 's-resize';
36550 Roo.bootstrap.layout.Split.call(this, config);
36552 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36553 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36554 this.split.el.addClass("roo-layout-split-v");
36556 var size = config.initialSize || config.height;
36557 if(typeof size != "undefined"){
36558 this.el.setHeight(size);
36562 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36563 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36564 getBox : function(){
36565 if(this.collapsed){
36566 return this.collapsedEl.getBox();
36568 var box = this.el.getBox();
36570 var sh = this.split.el.getHeight();
36577 updateBox : function(box){
36578 if(this.split && !this.collapsed){
36579 var sh = this.split.el.getHeight();
36582 this.split.el.setLeft(box.x);
36583 this.split.el.setTop(box.y-sh);
36584 this.split.el.setWidth(box.width);
36586 if(this.collapsed){
36587 this.updateBody(box.width, null);
36589 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36593 Roo.bootstrap.layout.East = function(config){
36594 config.region = "east";
36595 config.cursor = "e-resize";
36596 Roo.bootstrap.layout.Split.call(this, config);
36598 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36599 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36600 this.split.el.addClass("roo-layout-split-h");
36602 var size = config.initialSize || config.width;
36603 if(typeof size != "undefined"){
36604 this.el.setWidth(size);
36607 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36608 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36609 getBox : function(){
36610 if(this.collapsed){
36611 return this.collapsedEl.getBox();
36613 var box = this.el.getBox();
36615 var sw = this.split.el.getWidth();
36622 updateBox : function(box){
36623 if(this.split && !this.collapsed){
36624 var sw = this.split.el.getWidth();
36626 this.split.el.setLeft(box.x);
36627 this.split.el.setTop(box.y);
36628 this.split.el.setHeight(box.height);
36631 if(this.collapsed){
36632 this.updateBody(null, box.height);
36634 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36638 Roo.bootstrap.layout.West = function(config){
36639 config.region = "west";
36640 config.cursor = "w-resize";
36642 Roo.bootstrap.layout.Split.call(this, config);
36644 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36645 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36646 this.split.el.addClass("roo-layout-split-h");
36650 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36651 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36653 onRender: function(ctr, pos)
36655 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36656 var size = this.config.initialSize || this.config.width;
36657 if(typeof size != "undefined"){
36658 this.el.setWidth(size);
36662 getBox : function(){
36663 if(this.collapsed){
36664 return this.collapsedEl.getBox();
36666 var box = this.el.getBox();
36668 box.width += this.split.el.getWidth();
36673 updateBox : function(box){
36674 if(this.split && !this.collapsed){
36675 var sw = this.split.el.getWidth();
36677 this.split.el.setLeft(box.x+box.width);
36678 this.split.el.setTop(box.y);
36679 this.split.el.setHeight(box.height);
36681 if(this.collapsed){
36682 this.updateBody(null, box.height);
36684 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36687 Roo.namespace("Roo.bootstrap.panel");/*
36689 * Ext JS Library 1.1.1
36690 * Copyright(c) 2006-2007, Ext JS, LLC.
36692 * Originally Released Under LGPL - original licence link has changed is not relivant.
36695 * <script type="text/javascript">
36698 * @class Roo.ContentPanel
36699 * @extends Roo.util.Observable
36700 * A basic ContentPanel element.
36701 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36702 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36703 * @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
36704 * @cfg {Boolean} closable True if the panel can be closed/removed
36705 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36706 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36707 * @cfg {Toolbar} toolbar A toolbar for this panel
36708 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36709 * @cfg {String} title The title for this panel
36710 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36711 * @cfg {String} url Calls {@link #setUrl} with this value
36712 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36713 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36714 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36715 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36716 * @cfg {Boolean} badges render the badges
36719 * Create a new ContentPanel.
36720 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36721 * @param {String/Object} config A string to set only the title or a config object
36722 * @param {String} content (optional) Set the HTML content for this panel
36723 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36725 Roo.bootstrap.panel.Content = function( config){
36727 this.tpl = config.tpl || false;
36729 var el = config.el;
36730 var content = config.content;
36732 if(config.autoCreate){ // xtype is available if this is called from factory
36735 this.el = Roo.get(el);
36736 if(!this.el && config && config.autoCreate){
36737 if(typeof config.autoCreate == "object"){
36738 if(!config.autoCreate.id){
36739 config.autoCreate.id = config.id||el;
36741 this.el = Roo.DomHelper.append(document.body,
36742 config.autoCreate, true);
36744 var elcfg = { tag: "div",
36745 cls: "roo-layout-inactive-content",
36749 elcfg.html = config.html;
36753 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36756 this.closable = false;
36757 this.loaded = false;
36758 this.active = false;
36761 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36763 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36765 this.wrapEl = this.el; //this.el.wrap();
36767 if (config.toolbar.items) {
36768 ti = config.toolbar.items ;
36769 delete config.toolbar.items ;
36773 this.toolbar.render(this.wrapEl, 'before');
36774 for(var i =0;i < ti.length;i++) {
36775 // Roo.log(['add child', items[i]]);
36776 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36778 this.toolbar.items = nitems;
36779 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36780 delete config.toolbar;
36784 // xtype created footer. - not sure if will work as we normally have to render first..
36785 if (this.footer && !this.footer.el && this.footer.xtype) {
36786 if (!this.wrapEl) {
36787 this.wrapEl = this.el.wrap();
36790 this.footer.container = this.wrapEl.createChild();
36792 this.footer = Roo.factory(this.footer, Roo);
36797 if(typeof config == "string"){
36798 this.title = config;
36800 Roo.apply(this, config);
36804 this.resizeEl = Roo.get(this.resizeEl, true);
36806 this.resizeEl = this.el;
36808 // handle view.xtype
36816 * Fires when this panel is activated.
36817 * @param {Roo.ContentPanel} this
36821 * @event deactivate
36822 * Fires when this panel is activated.
36823 * @param {Roo.ContentPanel} this
36825 "deactivate" : true,
36829 * Fires when this panel is resized if fitToFrame is true.
36830 * @param {Roo.ContentPanel} this
36831 * @param {Number} width The width after any component adjustments
36832 * @param {Number} height The height after any component adjustments
36838 * Fires when this tab is created
36839 * @param {Roo.ContentPanel} this
36850 if(this.autoScroll){
36851 this.resizeEl.setStyle("overflow", "auto");
36853 // fix randome scrolling
36854 //this.el.on('scroll', function() {
36855 // Roo.log('fix random scolling');
36856 // this.scrollTo('top',0);
36859 content = content || this.content;
36861 this.setContent(content);
36863 if(config && config.url){
36864 this.setUrl(this.url, this.params, this.loadOnce);
36869 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36871 if (this.view && typeof(this.view.xtype) != 'undefined') {
36872 this.view.el = this.el.appendChild(document.createElement("div"));
36873 this.view = Roo.factory(this.view);
36874 this.view.render && this.view.render(false, '');
36878 this.fireEvent('render', this);
36881 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36885 setRegion : function(region){
36886 this.region = region;
36887 this.setActiveClass(region && !this.background);
36891 setActiveClass: function(state)
36894 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36895 this.el.setStyle('position','relative');
36897 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36898 this.el.setStyle('position', 'absolute');
36903 * Returns the toolbar for this Panel if one was configured.
36904 * @return {Roo.Toolbar}
36906 getToolbar : function(){
36907 return this.toolbar;
36910 setActiveState : function(active)
36912 this.active = active;
36913 this.setActiveClass(active);
36915 if(this.fireEvent("deactivate", this) === false){
36920 this.fireEvent("activate", this);
36924 * Updates this panel's element
36925 * @param {String} content The new content
36926 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36928 setContent : function(content, loadScripts){
36929 this.el.update(content, loadScripts);
36932 ignoreResize : function(w, h){
36933 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36936 this.lastSize = {width: w, height: h};
36941 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36942 * @return {Roo.UpdateManager} The UpdateManager
36944 getUpdateManager : function(){
36945 return this.el.getUpdateManager();
36948 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36949 * @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:
36952 url: "your-url.php",
36953 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36954 callback: yourFunction,
36955 scope: yourObject, //(optional scope)
36958 text: "Loading...",
36963 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36964 * 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.
36965 * @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}
36966 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36967 * @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.
36968 * @return {Roo.ContentPanel} this
36971 var um = this.el.getUpdateManager();
36972 um.update.apply(um, arguments);
36978 * 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.
36979 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36980 * @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)
36981 * @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)
36982 * @return {Roo.UpdateManager} The UpdateManager
36984 setUrl : function(url, params, loadOnce){
36985 if(this.refreshDelegate){
36986 this.removeListener("activate", this.refreshDelegate);
36988 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36989 this.on("activate", this.refreshDelegate);
36990 return this.el.getUpdateManager();
36993 _handleRefresh : function(url, params, loadOnce){
36994 if(!loadOnce || !this.loaded){
36995 var updater = this.el.getUpdateManager();
36996 updater.update(url, params, this._setLoaded.createDelegate(this));
37000 _setLoaded : function(){
37001 this.loaded = true;
37005 * Returns this panel's id
37008 getId : function(){
37013 * Returns this panel's element - used by regiosn to add.
37014 * @return {Roo.Element}
37016 getEl : function(){
37017 return this.wrapEl || this.el;
37022 adjustForComponents : function(width, height)
37024 //Roo.log('adjustForComponents ');
37025 if(this.resizeEl != this.el){
37026 width -= this.el.getFrameWidth('lr');
37027 height -= this.el.getFrameWidth('tb');
37030 var te = this.toolbar.getEl();
37031 te.setWidth(width);
37032 height -= te.getHeight();
37035 var te = this.footer.getEl();
37036 te.setWidth(width);
37037 height -= te.getHeight();
37041 if(this.adjustments){
37042 width += this.adjustments[0];
37043 height += this.adjustments[1];
37045 return {"width": width, "height": height};
37048 setSize : function(width, height){
37049 if(this.fitToFrame && !this.ignoreResize(width, height)){
37050 if(this.fitContainer && this.resizeEl != this.el){
37051 this.el.setSize(width, height);
37053 var size = this.adjustForComponents(width, height);
37054 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37055 this.fireEvent('resize', this, size.width, size.height);
37060 * Returns this panel's title
37063 getTitle : function(){
37065 if (typeof(this.title) != 'object') {
37070 for (var k in this.title) {
37071 if (!this.title.hasOwnProperty(k)) {
37075 if (k.indexOf('-') >= 0) {
37076 var s = k.split('-');
37077 for (var i = 0; i<s.length; i++) {
37078 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37081 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37088 * Set this panel's title
37089 * @param {String} title
37091 setTitle : function(title){
37092 this.title = title;
37094 this.region.updatePanelTitle(this, title);
37099 * Returns true is this panel was configured to be closable
37100 * @return {Boolean}
37102 isClosable : function(){
37103 return this.closable;
37106 beforeSlide : function(){
37108 this.resizeEl.clip();
37111 afterSlide : function(){
37113 this.resizeEl.unclip();
37117 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37118 * Will fail silently if the {@link #setUrl} method has not been called.
37119 * This does not activate the panel, just updates its content.
37121 refresh : function(){
37122 if(this.refreshDelegate){
37123 this.loaded = false;
37124 this.refreshDelegate();
37129 * Destroys this panel
37131 destroy : function(){
37132 this.el.removeAllListeners();
37133 var tempEl = document.createElement("span");
37134 tempEl.appendChild(this.el.dom);
37135 tempEl.innerHTML = "";
37141 * form - if the content panel contains a form - this is a reference to it.
37142 * @type {Roo.form.Form}
37146 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37147 * This contains a reference to it.
37153 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37163 * @param {Object} cfg Xtype definition of item to add.
37167 getChildContainer: function () {
37168 return this.getEl();
37173 var ret = new Roo.factory(cfg);
37178 if (cfg.xtype.match(/^Form$/)) {
37181 //if (this.footer) {
37182 // el = this.footer.container.insertSibling(false, 'before');
37184 el = this.el.createChild();
37187 this.form = new Roo.form.Form(cfg);
37190 if ( this.form.allItems.length) {
37191 this.form.render(el.dom);
37195 // should only have one of theses..
37196 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37197 // views.. should not be just added - used named prop 'view''
37199 cfg.el = this.el.appendChild(document.createElement("div"));
37202 var ret = new Roo.factory(cfg);
37204 ret.render && ret.render(false, ''); // render blank..
37214 * @class Roo.bootstrap.panel.Grid
37215 * @extends Roo.bootstrap.panel.Content
37217 * Create a new GridPanel.
37218 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37219 * @param {Object} config A the config object
37225 Roo.bootstrap.panel.Grid = function(config)
37229 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37230 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37232 config.el = this.wrapper;
37233 //this.el = this.wrapper;
37235 if (config.container) {
37236 // ctor'ed from a Border/panel.grid
37239 this.wrapper.setStyle("overflow", "hidden");
37240 this.wrapper.addClass('roo-grid-container');
37245 if(config.toolbar){
37246 var tool_el = this.wrapper.createChild();
37247 this.toolbar = Roo.factory(config.toolbar);
37249 if (config.toolbar.items) {
37250 ti = config.toolbar.items ;
37251 delete config.toolbar.items ;
37255 this.toolbar.render(tool_el);
37256 for(var i =0;i < ti.length;i++) {
37257 // Roo.log(['add child', items[i]]);
37258 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37260 this.toolbar.items = nitems;
37262 delete config.toolbar;
37265 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37266 config.grid.scrollBody = true;;
37267 config.grid.monitorWindowResize = false; // turn off autosizing
37268 config.grid.autoHeight = false;
37269 config.grid.autoWidth = false;
37271 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37273 if (config.background) {
37274 // render grid on panel activation (if panel background)
37275 this.on('activate', function(gp) {
37276 if (!gp.grid.rendered) {
37277 gp.grid.render(this.wrapper);
37278 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37283 this.grid.render(this.wrapper);
37284 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37287 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37288 // ??? needed ??? config.el = this.wrapper;
37293 // xtype created footer. - not sure if will work as we normally have to render first..
37294 if (this.footer && !this.footer.el && this.footer.xtype) {
37296 var ctr = this.grid.getView().getFooterPanel(true);
37297 this.footer.dataSource = this.grid.dataSource;
37298 this.footer = Roo.factory(this.footer, Roo);
37299 this.footer.render(ctr);
37309 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37310 getId : function(){
37311 return this.grid.id;
37315 * Returns the grid for this panel
37316 * @return {Roo.bootstrap.Table}
37318 getGrid : function(){
37322 setSize : function(width, height){
37323 if(!this.ignoreResize(width, height)){
37324 var grid = this.grid;
37325 var size = this.adjustForComponents(width, height);
37326 var gridel = grid.getGridEl();
37327 gridel.setSize(size.width, size.height);
37329 var thd = grid.getGridEl().select('thead',true).first();
37330 var tbd = grid.getGridEl().select('tbody', true).first();
37332 tbd.setSize(width, height - thd.getHeight());
37341 beforeSlide : function(){
37342 this.grid.getView().scroller.clip();
37345 afterSlide : function(){
37346 this.grid.getView().scroller.unclip();
37349 destroy : function(){
37350 this.grid.destroy();
37352 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37357 * @class Roo.bootstrap.panel.Nest
37358 * @extends Roo.bootstrap.panel.Content
37360 * Create a new Panel, that can contain a layout.Border.
37363 * @param {Roo.BorderLayout} layout The layout for this panel
37364 * @param {String/Object} config A string to set only the title or a config object
37366 Roo.bootstrap.panel.Nest = function(config)
37368 // construct with only one argument..
37369 /* FIXME - implement nicer consturctors
37370 if (layout.layout) {
37372 layout = config.layout;
37373 delete config.layout;
37375 if (layout.xtype && !layout.getEl) {
37376 // then layout needs constructing..
37377 layout = Roo.factory(layout, Roo);
37381 config.el = config.layout.getEl();
37383 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37385 config.layout.monitorWindowResize = false; // turn off autosizing
37386 this.layout = config.layout;
37387 this.layout.getEl().addClass("roo-layout-nested-layout");
37394 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37396 setSize : function(width, height){
37397 if(!this.ignoreResize(width, height)){
37398 var size = this.adjustForComponents(width, height);
37399 var el = this.layout.getEl();
37400 if (size.height < 1) {
37401 el.setWidth(size.width);
37403 el.setSize(size.width, size.height);
37405 var touch = el.dom.offsetWidth;
37406 this.layout.layout();
37407 // ie requires a double layout on the first pass
37408 if(Roo.isIE && !this.initialized){
37409 this.initialized = true;
37410 this.layout.layout();
37415 // activate all subpanels if not currently active..
37417 setActiveState : function(active){
37418 this.active = active;
37419 this.setActiveClass(active);
37422 this.fireEvent("deactivate", this);
37426 this.fireEvent("activate", this);
37427 // not sure if this should happen before or after..
37428 if (!this.layout) {
37429 return; // should not happen..
37432 for (var r in this.layout.regions) {
37433 reg = this.layout.getRegion(r);
37434 if (reg.getActivePanel()) {
37435 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37436 reg.setActivePanel(reg.getActivePanel());
37439 if (!reg.panels.length) {
37442 reg.showPanel(reg.getPanel(0));
37451 * Returns the nested BorderLayout for this panel
37452 * @return {Roo.BorderLayout}
37454 getLayout : function(){
37455 return this.layout;
37459 * Adds a xtype elements to the layout of the nested panel
37463 xtype : 'ContentPanel',
37470 xtype : 'NestedLayoutPanel',
37476 items : [ ... list of content panels or nested layout panels.. ]
37480 * @param {Object} cfg Xtype definition of item to add.
37482 addxtype : function(cfg) {
37483 return this.layout.addxtype(cfg);
37488 * Ext JS Library 1.1.1
37489 * Copyright(c) 2006-2007, Ext JS, LLC.
37491 * Originally Released Under LGPL - original licence link has changed is not relivant.
37494 * <script type="text/javascript">
37497 * @class Roo.TabPanel
37498 * @extends Roo.util.Observable
37499 * A lightweight tab container.
37503 // basic tabs 1, built from existing content
37504 var tabs = new Roo.TabPanel("tabs1");
37505 tabs.addTab("script", "View Script");
37506 tabs.addTab("markup", "View Markup");
37507 tabs.activate("script");
37509 // more advanced tabs, built from javascript
37510 var jtabs = new Roo.TabPanel("jtabs");
37511 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37513 // set up the UpdateManager
37514 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37515 var updater = tab2.getUpdateManager();
37516 updater.setDefaultUrl("ajax1.htm");
37517 tab2.on('activate', updater.refresh, updater, true);
37519 // Use setUrl for Ajax loading
37520 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37521 tab3.setUrl("ajax2.htm", null, true);
37524 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37527 jtabs.activate("jtabs-1");
37530 * Create a new TabPanel.
37531 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37532 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37534 Roo.bootstrap.panel.Tabs = function(config){
37536 * The container element for this TabPanel.
37537 * @type Roo.Element
37539 this.el = Roo.get(config.el);
37542 if(typeof config == "boolean"){
37543 this.tabPosition = config ? "bottom" : "top";
37545 Roo.apply(this, config);
37549 if(this.tabPosition == "bottom"){
37550 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37551 this.el.addClass("roo-tabs-bottom");
37553 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37554 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37555 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37557 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37559 if(this.tabPosition != "bottom"){
37560 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37561 * @type Roo.Element
37563 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37564 this.el.addClass("roo-tabs-top");
37568 this.bodyEl.setStyle("position", "relative");
37570 this.active = null;
37571 this.activateDelegate = this.activate.createDelegate(this);
37576 * Fires when the active tab changes
37577 * @param {Roo.TabPanel} this
37578 * @param {Roo.TabPanelItem} activePanel The new active tab
37582 * @event beforetabchange
37583 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37584 * @param {Roo.TabPanel} this
37585 * @param {Object} e Set cancel to true on this object to cancel the tab change
37586 * @param {Roo.TabPanelItem} tab The tab being changed to
37588 "beforetabchange" : true
37591 Roo.EventManager.onWindowResize(this.onResize, this);
37592 this.cpad = this.el.getPadding("lr");
37593 this.hiddenCount = 0;
37596 // toolbar on the tabbar support...
37597 if (this.toolbar) {
37598 alert("no toolbar support yet");
37599 this.toolbar = false;
37601 var tcfg = this.toolbar;
37602 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37603 this.toolbar = new Roo.Toolbar(tcfg);
37604 if (Roo.isSafari) {
37605 var tbl = tcfg.container.child('table', true);
37606 tbl.setAttribute('width', '100%');
37614 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37617 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37619 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37621 tabPosition : "top",
37623 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37625 currentTabWidth : 0,
37627 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37631 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37635 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37637 preferredTabWidth : 175,
37639 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37641 resizeTabs : false,
37643 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37645 monitorResize : true,
37647 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37652 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37653 * @param {String} id The id of the div to use <b>or create</b>
37654 * @param {String} text The text for the tab
37655 * @param {String} content (optional) Content to put in the TabPanelItem body
37656 * @param {Boolean} closable (optional) True to create a close icon on the tab
37657 * @return {Roo.TabPanelItem} The created TabPanelItem
37659 addTab : function(id, text, content, closable, tpl)
37661 var item = new Roo.bootstrap.panel.TabItem({
37665 closable : closable,
37668 this.addTabItem(item);
37670 item.setContent(content);
37676 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37677 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37678 * @return {Roo.TabPanelItem}
37680 getTab : function(id){
37681 return this.items[id];
37685 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37686 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37688 hideTab : function(id){
37689 var t = this.items[id];
37692 this.hiddenCount++;
37693 this.autoSizeTabs();
37698 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37699 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37701 unhideTab : function(id){
37702 var t = this.items[id];
37704 t.setHidden(false);
37705 this.hiddenCount--;
37706 this.autoSizeTabs();
37711 * Adds an existing {@link Roo.TabPanelItem}.
37712 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37714 addTabItem : function(item){
37715 this.items[item.id] = item;
37716 this.items.push(item);
37717 // if(this.resizeTabs){
37718 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37719 // this.autoSizeTabs();
37721 // item.autoSize();
37726 * Removes a {@link Roo.TabPanelItem}.
37727 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37729 removeTab : function(id){
37730 var items = this.items;
37731 var tab = items[id];
37732 if(!tab) { return; }
37733 var index = items.indexOf(tab);
37734 if(this.active == tab && items.length > 1){
37735 var newTab = this.getNextAvailable(index);
37740 this.stripEl.dom.removeChild(tab.pnode.dom);
37741 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37742 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37744 items.splice(index, 1);
37745 delete this.items[tab.id];
37746 tab.fireEvent("close", tab);
37747 tab.purgeListeners();
37748 this.autoSizeTabs();
37751 getNextAvailable : function(start){
37752 var items = this.items;
37754 // look for a next tab that will slide over to
37755 // replace the one being removed
37756 while(index < items.length){
37757 var item = items[++index];
37758 if(item && !item.isHidden()){
37762 // if one isn't found select the previous tab (on the left)
37765 var item = items[--index];
37766 if(item && !item.isHidden()){
37774 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37775 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37777 disableTab : function(id){
37778 var tab = this.items[id];
37779 if(tab && this.active != tab){
37785 * Enables a {@link Roo.TabPanelItem} that is disabled.
37786 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37788 enableTab : function(id){
37789 var tab = this.items[id];
37794 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37795 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37796 * @return {Roo.TabPanelItem} The TabPanelItem.
37798 activate : function(id){
37799 var tab = this.items[id];
37803 if(tab == this.active || tab.disabled){
37807 this.fireEvent("beforetabchange", this, e, tab);
37808 if(e.cancel !== true && !tab.disabled){
37810 this.active.hide();
37812 this.active = this.items[id];
37813 this.active.show();
37814 this.fireEvent("tabchange", this, this.active);
37820 * Gets the active {@link Roo.TabPanelItem}.
37821 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37823 getActiveTab : function(){
37824 return this.active;
37828 * Updates the tab body element to fit the height of the container element
37829 * for overflow scrolling
37830 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37832 syncHeight : function(targetHeight){
37833 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37834 var bm = this.bodyEl.getMargins();
37835 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37836 this.bodyEl.setHeight(newHeight);
37840 onResize : function(){
37841 if(this.monitorResize){
37842 this.autoSizeTabs();
37847 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37849 beginUpdate : function(){
37850 this.updating = true;
37854 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37856 endUpdate : function(){
37857 this.updating = false;
37858 this.autoSizeTabs();
37862 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37864 autoSizeTabs : function(){
37865 var count = this.items.length;
37866 var vcount = count - this.hiddenCount;
37867 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37870 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37871 var availWidth = Math.floor(w / vcount);
37872 var b = this.stripBody;
37873 if(b.getWidth() > w){
37874 var tabs = this.items;
37875 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37876 if(availWidth < this.minTabWidth){
37877 /*if(!this.sleft){ // incomplete scrolling code
37878 this.createScrollButtons();
37881 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37884 if(this.currentTabWidth < this.preferredTabWidth){
37885 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37891 * Returns the number of tabs in this TabPanel.
37894 getCount : function(){
37895 return this.items.length;
37899 * Resizes all the tabs to the passed width
37900 * @param {Number} The new width
37902 setTabWidth : function(width){
37903 this.currentTabWidth = width;
37904 for(var i = 0, len = this.items.length; i < len; i++) {
37905 if(!this.items[i].isHidden()) {
37906 this.items[i].setWidth(width);
37912 * Destroys this TabPanel
37913 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37915 destroy : function(removeEl){
37916 Roo.EventManager.removeResizeListener(this.onResize, this);
37917 for(var i = 0, len = this.items.length; i < len; i++){
37918 this.items[i].purgeListeners();
37920 if(removeEl === true){
37921 this.el.update("");
37926 createStrip : function(container)
37928 var strip = document.createElement("nav");
37929 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37930 container.appendChild(strip);
37934 createStripList : function(strip)
37936 // div wrapper for retard IE
37937 // returns the "tr" element.
37938 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37939 //'<div class="x-tabs-strip-wrap">'+
37940 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37941 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37942 return strip.firstChild; //.firstChild.firstChild.firstChild;
37944 createBody : function(container)
37946 var body = document.createElement("div");
37947 Roo.id(body, "tab-body");
37948 //Roo.fly(body).addClass("x-tabs-body");
37949 Roo.fly(body).addClass("tab-content");
37950 container.appendChild(body);
37953 createItemBody :function(bodyEl, id){
37954 var body = Roo.getDom(id);
37956 body = document.createElement("div");
37959 //Roo.fly(body).addClass("x-tabs-item-body");
37960 Roo.fly(body).addClass("tab-pane");
37961 bodyEl.insertBefore(body, bodyEl.firstChild);
37965 createStripElements : function(stripEl, text, closable, tpl)
37967 var td = document.createElement("li"); // was td..
37970 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37973 stripEl.appendChild(td);
37975 td.className = "x-tabs-closable";
37976 if(!this.closeTpl){
37977 this.closeTpl = new Roo.Template(
37978 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37979 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37980 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37983 var el = this.closeTpl.overwrite(td, {"text": text});
37984 var close = el.getElementsByTagName("div")[0];
37985 var inner = el.getElementsByTagName("em")[0];
37986 return {"el": el, "close": close, "inner": inner};
37989 // not sure what this is..
37990 // if(!this.tabTpl){
37991 //this.tabTpl = new Roo.Template(
37992 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37993 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37995 // this.tabTpl = new Roo.Template(
37996 // '<a href="#">' +
37997 // '<span unselectable="on"' +
37998 // (this.disableTooltips ? '' : ' title="{text}"') +
37999 // ' >{text}</span></a>'
38005 var template = tpl || this.tabTpl || false;
38009 template = new Roo.Template(
38011 '<span unselectable="on"' +
38012 (this.disableTooltips ? '' : ' title="{text}"') +
38013 ' >{text}</span></a>'
38017 switch (typeof(template)) {
38021 template = new Roo.Template(template);
38027 var el = template.overwrite(td, {"text": text});
38029 var inner = el.getElementsByTagName("span")[0];
38031 return {"el": el, "inner": inner};
38039 * @class Roo.TabPanelItem
38040 * @extends Roo.util.Observable
38041 * Represents an individual item (tab plus body) in a TabPanel.
38042 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38043 * @param {String} id The id of this TabPanelItem
38044 * @param {String} text The text for the tab of this TabPanelItem
38045 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38047 Roo.bootstrap.panel.TabItem = function(config){
38049 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38050 * @type Roo.TabPanel
38052 this.tabPanel = config.panel;
38054 * The id for this TabPanelItem
38057 this.id = config.id;
38059 this.disabled = false;
38061 this.text = config.text;
38063 this.loaded = false;
38064 this.closable = config.closable;
38067 * The body element for this TabPanelItem.
38068 * @type Roo.Element
38070 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38071 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38072 this.bodyEl.setStyle("display", "block");
38073 this.bodyEl.setStyle("zoom", "1");
38074 //this.hideAction();
38076 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38078 this.el = Roo.get(els.el);
38079 this.inner = Roo.get(els.inner, true);
38080 this.textEl = Roo.get(this.el.dom.firstChild, true);
38081 this.pnode = Roo.get(els.el.parentNode, true);
38082 // this.el.on("mousedown", this.onTabMouseDown, this);
38083 this.el.on("click", this.onTabClick, this);
38085 if(config.closable){
38086 var c = Roo.get(els.close, true);
38087 c.dom.title = this.closeText;
38088 c.addClassOnOver("close-over");
38089 c.on("click", this.closeClick, this);
38095 * Fires when this tab becomes the active tab.
38096 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38097 * @param {Roo.TabPanelItem} this
38101 * @event beforeclose
38102 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38103 * @param {Roo.TabPanelItem} this
38104 * @param {Object} e Set cancel to true on this object to cancel the close.
38106 "beforeclose": true,
38109 * Fires when this tab is closed.
38110 * @param {Roo.TabPanelItem} this
38114 * @event deactivate
38115 * Fires when this tab is no longer the active tab.
38116 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38117 * @param {Roo.TabPanelItem} this
38119 "deactivate" : true
38121 this.hidden = false;
38123 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38126 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38128 purgeListeners : function(){
38129 Roo.util.Observable.prototype.purgeListeners.call(this);
38130 this.el.removeAllListeners();
38133 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38136 this.pnode.addClass("active");
38139 this.tabPanel.stripWrap.repaint();
38141 this.fireEvent("activate", this.tabPanel, this);
38145 * Returns true if this tab is the active tab.
38146 * @return {Boolean}
38148 isActive : function(){
38149 return this.tabPanel.getActiveTab() == this;
38153 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38156 this.pnode.removeClass("active");
38158 this.fireEvent("deactivate", this.tabPanel, this);
38161 hideAction : function(){
38162 this.bodyEl.hide();
38163 this.bodyEl.setStyle("position", "absolute");
38164 this.bodyEl.setLeft("-20000px");
38165 this.bodyEl.setTop("-20000px");
38168 showAction : function(){
38169 this.bodyEl.setStyle("position", "relative");
38170 this.bodyEl.setTop("");
38171 this.bodyEl.setLeft("");
38172 this.bodyEl.show();
38176 * Set the tooltip for the tab.
38177 * @param {String} tooltip The tab's tooltip
38179 setTooltip : function(text){
38180 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38181 this.textEl.dom.qtip = text;
38182 this.textEl.dom.removeAttribute('title');
38184 this.textEl.dom.title = text;
38188 onTabClick : function(e){
38189 e.preventDefault();
38190 this.tabPanel.activate(this.id);
38193 onTabMouseDown : function(e){
38194 e.preventDefault();
38195 this.tabPanel.activate(this.id);
38198 getWidth : function(){
38199 return this.inner.getWidth();
38202 setWidth : function(width){
38203 var iwidth = width - this.pnode.getPadding("lr");
38204 this.inner.setWidth(iwidth);
38205 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38206 this.pnode.setWidth(width);
38210 * Show or hide the tab
38211 * @param {Boolean} hidden True to hide or false to show.
38213 setHidden : function(hidden){
38214 this.hidden = hidden;
38215 this.pnode.setStyle("display", hidden ? "none" : "");
38219 * Returns true if this tab is "hidden"
38220 * @return {Boolean}
38222 isHidden : function(){
38223 return this.hidden;
38227 * Returns the text for this tab
38230 getText : function(){
38234 autoSize : function(){
38235 //this.el.beginMeasure();
38236 this.textEl.setWidth(1);
38238 * #2804 [new] Tabs in Roojs
38239 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38241 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38242 //this.el.endMeasure();
38246 * Sets the text for the tab (Note: this also sets the tooltip text)
38247 * @param {String} text The tab's text and tooltip
38249 setText : function(text){
38251 this.textEl.update(text);
38252 this.setTooltip(text);
38253 //if(!this.tabPanel.resizeTabs){
38254 // this.autoSize();
38258 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38260 activate : function(){
38261 this.tabPanel.activate(this.id);
38265 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38267 disable : function(){
38268 if(this.tabPanel.active != this){
38269 this.disabled = true;
38270 this.pnode.addClass("disabled");
38275 * Enables this TabPanelItem if it was previously disabled.
38277 enable : function(){
38278 this.disabled = false;
38279 this.pnode.removeClass("disabled");
38283 * Sets the content for this TabPanelItem.
38284 * @param {String} content The content
38285 * @param {Boolean} loadScripts true to look for and load scripts
38287 setContent : function(content, loadScripts){
38288 this.bodyEl.update(content, loadScripts);
38292 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38293 * @return {Roo.UpdateManager} The UpdateManager
38295 getUpdateManager : function(){
38296 return this.bodyEl.getUpdateManager();
38300 * Set a URL to be used to load the content for this TabPanelItem.
38301 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38302 * @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)
38303 * @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)
38304 * @return {Roo.UpdateManager} The UpdateManager
38306 setUrl : function(url, params, loadOnce){
38307 if(this.refreshDelegate){
38308 this.un('activate', this.refreshDelegate);
38310 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38311 this.on("activate", this.refreshDelegate);
38312 return this.bodyEl.getUpdateManager();
38316 _handleRefresh : function(url, params, loadOnce){
38317 if(!loadOnce || !this.loaded){
38318 var updater = this.bodyEl.getUpdateManager();
38319 updater.update(url, params, this._setLoaded.createDelegate(this));
38324 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38325 * Will fail silently if the setUrl method has not been called.
38326 * This does not activate the panel, just updates its content.
38328 refresh : function(){
38329 if(this.refreshDelegate){
38330 this.loaded = false;
38331 this.refreshDelegate();
38336 _setLoaded : function(){
38337 this.loaded = true;
38341 closeClick : function(e){
38344 this.fireEvent("beforeclose", this, o);
38345 if(o.cancel !== true){
38346 this.tabPanel.removeTab(this.id);
38350 * The text displayed in the tooltip for the close icon.
38353 closeText : "Close this tab"
38356 * This script refer to:
38357 * Title: International Telephone Input
38358 * Author: Jack O'Connor
38359 * Code version: v12.1.12
38360 * Availability: https://github.com/jackocnr/intl-tel-input.git
38363 Roo.bootstrap.PhoneInputData = function() {
38366 "Afghanistan (افغانستان)",
38371 "Albania (Shqipëri)",
38376 "Algeria (الجزائر)",
38401 "Antigua and Barbuda",
38411 "Armenia (Հայաստան)",
38427 "Austria (Österreich)",
38432 "Azerbaijan (Azərbaycan)",
38442 "Bahrain (البحرين)",
38447 "Bangladesh (বাংলাদেশ)",
38457 "Belarus (Беларусь)",
38462 "Belgium (België)",
38492 "Bosnia and Herzegovina (Босна и Херцеговина)",
38507 "British Indian Ocean Territory",
38512 "British Virgin Islands",
38522 "Bulgaria (България)",
38532 "Burundi (Uburundi)",
38537 "Cambodia (កម្ពុជា)",
38542 "Cameroon (Cameroun)",
38551 ["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"]
38554 "Cape Verde (Kabu Verdi)",
38559 "Caribbean Netherlands",
38570 "Central African Republic (République centrafricaine)",
38590 "Christmas Island",
38596 "Cocos (Keeling) Islands",
38607 "Comoros (جزر القمر)",
38612 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38617 "Congo (Republic) (Congo-Brazzaville)",
38637 "Croatia (Hrvatska)",
38658 "Czech Republic (Česká republika)",
38663 "Denmark (Danmark)",
38678 "Dominican Republic (República Dominicana)",
38682 ["809", "829", "849"]
38700 "Equatorial Guinea (Guinea Ecuatorial)",
38720 "Falkland Islands (Islas Malvinas)",
38725 "Faroe Islands (Føroyar)",
38746 "French Guiana (Guyane française)",
38751 "French Polynesia (Polynésie française)",
38766 "Georgia (საქართველო)",
38771 "Germany (Deutschland)",
38791 "Greenland (Kalaallit Nunaat)",
38828 "Guinea-Bissau (Guiné Bissau)",
38853 "Hungary (Magyarország)",
38858 "Iceland (Ísland)",
38878 "Iraq (العراق)",
38894 "Israel (ישראל)",
38921 "Jordan (الأردن)",
38926 "Kazakhstan (Казахстан)",
38947 "Kuwait (الكويت)",
38952 "Kyrgyzstan (Кыргызстан)",
38962 "Latvia (Latvija)",
38967 "Lebanon (لبنان)",
38982 "Libya (ليبيا)",
38992 "Lithuania (Lietuva)",
39007 "Macedonia (FYROM) (Македонија)",
39012 "Madagascar (Madagasikara)",
39042 "Marshall Islands",
39052 "Mauritania (موريتانيا)",
39057 "Mauritius (Moris)",
39078 "Moldova (Republica Moldova)",
39088 "Mongolia (Монгол)",
39093 "Montenegro (Crna Gora)",
39103 "Morocco (المغرب)",
39109 "Mozambique (Moçambique)",
39114 "Myanmar (Burma) (မြန်မာ)",
39119 "Namibia (Namibië)",
39134 "Netherlands (Nederland)",
39139 "New Caledonia (Nouvelle-Calédonie)",
39174 "North Korea (조선 민주주의 인민 공화국)",
39179 "Northern Mariana Islands",
39195 "Pakistan (پاکستان)",
39205 "Palestine (فلسطين)",
39215 "Papua New Guinea",
39257 "Réunion (La Réunion)",
39263 "Romania (România)",
39279 "Saint Barthélemy",
39290 "Saint Kitts and Nevis",
39300 "Saint Martin (Saint-Martin (partie française))",
39306 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39311 "Saint Vincent and the Grenadines",
39326 "São Tomé and Príncipe (São Tomé e Príncipe)",
39331 "Saudi Arabia (المملكة العربية السعودية)",
39336 "Senegal (Sénégal)",
39366 "Slovakia (Slovensko)",
39371 "Slovenia (Slovenija)",
39381 "Somalia (Soomaaliya)",
39391 "South Korea (대한민국)",
39396 "South Sudan (جنوب السودان)",
39406 "Sri Lanka (ශ්රී ලංකාව)",
39411 "Sudan (السودان)",
39421 "Svalbard and Jan Mayen",
39432 "Sweden (Sverige)",
39437 "Switzerland (Schweiz)",
39442 "Syria (سوريا)",
39487 "Trinidad and Tobago",
39492 "Tunisia (تونس)",
39497 "Turkey (Türkiye)",
39507 "Turks and Caicos Islands",
39517 "U.S. Virgin Islands",
39527 "Ukraine (Україна)",
39532 "United Arab Emirates (الإمارات العربية المتحدة)",
39554 "Uzbekistan (Oʻzbekiston)",
39564 "Vatican City (Città del Vaticano)",
39575 "Vietnam (Việt Nam)",
39580 "Wallis and Futuna (Wallis-et-Futuna)",
39585 "Western Sahara (الصحراء الغربية)",
39591 "Yemen (اليمن)",
39615 * This script refer to:
39616 * Title: International Telephone Input
39617 * Author: Jack O'Connor
39618 * Code version: v12.1.12
39619 * Availability: https://github.com/jackocnr/intl-tel-input.git
39623 * @class Roo.bootstrap.PhoneInput
39624 * @extends Roo.bootstrap.TriggerField
39625 * An input with International dial-code selection
39627 * @cfg {String} defaultDialCode default '+852'
39628 * @cfg {Array} preferedCountries default []
39631 * Create a new PhoneInput.
39632 * @param {Object} config Configuration options
39635 Roo.bootstrap.PhoneInput = function(config) {
39636 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39639 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39641 listWidth: undefined,
39643 selectedClass: 'active',
39645 invalidClass : "has-warning",
39647 validClass: 'has-success',
39649 allowed: '0123456789',
39652 * @cfg {String} defaultDialCode The default dial code when initializing the input
39654 defaultDialCode: '+852',
39657 * @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
39659 preferedCountries: false,
39661 getAutoCreate : function()
39663 var data = Roo.bootstrap.PhoneInputData();
39664 var align = this.labelAlign || this.parentLabelAlign();
39667 this.allCountries = [];
39668 this.dialCodeMapping = [];
39670 for (var i = 0; i < data.length; i++) {
39672 this.allCountries[i] = {
39676 priority: c[3] || 0,
39677 areaCodes: c[4] || null
39679 this.dialCodeMapping[c[2]] = {
39682 priority: c[3] || 0,
39683 areaCodes: c[4] || null
39695 cls : 'form-control tel-input',
39696 autocomplete: 'new-password'
39699 var hiddenInput = {
39702 cls: 'hidden-tel-input'
39706 hiddenInput.name = this.name;
39709 if (this.disabled) {
39710 input.disabled = true;
39713 var flag_container = {
39730 cls: this.hasFeedback ? 'has-feedback' : '',
39736 cls: 'dial-code-holder',
39743 cls: 'roo-select2-container input-group',
39750 if (this.fieldLabel.length) {
39753 tooltip: 'This field is required'
39759 cls: 'control-label',
39765 html: this.fieldLabel
39768 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39774 if(this.indicatorpos == 'right') {
39775 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39782 if(align == 'left') {
39790 if(this.labelWidth > 12){
39791 label.style = "width: " + this.labelWidth + 'px';
39793 if(this.labelWidth < 13 && this.labelmd == 0){
39794 this.labelmd = this.labelWidth;
39796 if(this.labellg > 0){
39797 label.cls += ' col-lg-' + this.labellg;
39798 input.cls += ' col-lg-' + (12 - this.labellg);
39800 if(this.labelmd > 0){
39801 label.cls += ' col-md-' + this.labelmd;
39802 container.cls += ' col-md-' + (12 - this.labelmd);
39804 if(this.labelsm > 0){
39805 label.cls += ' col-sm-' + this.labelsm;
39806 container.cls += ' col-sm-' + (12 - this.labelsm);
39808 if(this.labelxs > 0){
39809 label.cls += ' col-xs-' + this.labelxs;
39810 container.cls += ' col-xs-' + (12 - this.labelxs);
39820 var settings = this;
39822 ['xs','sm','md','lg'].map(function(size){
39823 if (settings[size]) {
39824 cfg.cls += ' col-' + size + '-' + settings[size];
39828 this.store = new Roo.data.Store({
39829 proxy : new Roo.data.MemoryProxy({}),
39830 reader : new Roo.data.JsonReader({
39841 'name' : 'dialCode',
39845 'name' : 'priority',
39849 'name' : 'areaCodes',
39856 if(!this.preferedCountries) {
39857 this.preferedCountries = [
39864 var p = this.preferedCountries.reverse();
39867 for (var i = 0; i < p.length; i++) {
39868 for (var j = 0; j < this.allCountries.length; j++) {
39869 if(this.allCountries[j].iso2 == p[i]) {
39870 var t = this.allCountries[j];
39871 this.allCountries.splice(j,1);
39872 this.allCountries.unshift(t);
39878 this.store.proxy.data = {
39880 data: this.allCountries
39886 initEvents : function()
39889 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39891 this.indicator = this.indicatorEl();
39892 this.flag = this.flagEl();
39893 this.dialCodeHolder = this.dialCodeHolderEl();
39895 this.trigger = this.el.select('div.flag-box',true).first();
39896 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39901 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39902 _this.list.setWidth(lw);
39905 this.list.on('mouseover', this.onViewOver, this);
39906 this.list.on('mousemove', this.onViewMove, this);
39907 this.inputEl().on("keyup", this.onKeyUp, this);
39909 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39911 this.view = new Roo.View(this.list, this.tpl, {
39912 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39915 this.view.on('click', this.onViewClick, this);
39916 this.setValue(this.defaultDialCode);
39919 onTriggerClick : function(e)
39921 Roo.log('trigger click');
39926 if(this.isExpanded()){
39928 this.hasFocus = false;
39930 this.store.load({});
39931 this.hasFocus = true;
39936 isExpanded : function()
39938 return this.list.isVisible();
39941 collapse : function()
39943 if(!this.isExpanded()){
39947 Roo.get(document).un('mousedown', this.collapseIf, this);
39948 Roo.get(document).un('mousewheel', this.collapseIf, this);
39949 this.fireEvent('collapse', this);
39953 expand : function()
39957 if(this.isExpanded() || !this.hasFocus){
39961 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39962 this.list.setWidth(lw);
39965 this.restrictHeight();
39967 Roo.get(document).on('mousedown', this.collapseIf, this);
39968 Roo.get(document).on('mousewheel', this.collapseIf, this);
39970 this.fireEvent('expand', this);
39973 restrictHeight : function()
39975 this.list.alignTo(this.inputEl(), this.listAlign);
39976 this.list.alignTo(this.inputEl(), this.listAlign);
39979 onViewOver : function(e, t)
39981 if(this.inKeyMode){
39984 var item = this.view.findItemFromChild(t);
39987 var index = this.view.indexOf(item);
39988 this.select(index, false);
39993 onViewClick : function(view, doFocus, el, e)
39995 var index = this.view.getSelectedIndexes()[0];
39997 var r = this.store.getAt(index);
40000 this.onSelect(r, index);
40002 if(doFocus !== false && !this.blockFocus){
40003 this.inputEl().focus();
40007 onViewMove : function(e, t)
40009 this.inKeyMode = false;
40012 select : function(index, scrollIntoView)
40014 this.selectedIndex = index;
40015 this.view.select(index);
40016 if(scrollIntoView !== false){
40017 var el = this.view.getNode(index);
40019 this.list.scrollChildIntoView(el, false);
40024 createList : function()
40026 this.list = Roo.get(document.body).createChild({
40028 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40029 style: 'display:none'
40031 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
40034 collapseIf : function(e)
40036 var in_combo = e.within(this.el);
40037 var in_list = e.within(this.list);
40038 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40040 if (in_combo || in_list || is_list) {
40046 onSelect : function(record, index)
40048 if(this.fireEvent('beforeselect', this, record, index) !== false){
40050 this.setFlagClass(record.data.iso2);
40051 this.setDialCode(record.data.dialCode);
40052 this.hasFocus = false;
40054 this.fireEvent('select', this, record, index);
40058 flagEl : function()
40060 var flag = this.el.select('div.flag',true).first();
40067 dialCodeHolderEl : function()
40069 var d = this.el.select('input.dial-code-holder',true).first();
40076 setDialCode : function(v)
40078 this.dialCodeHolder.dom.value = '+'+v;
40081 setFlagClass : function(n)
40083 this.flag.dom.className = 'flag '+n;
40086 getValue : function()
40088 var v = this.inputEl().getValue();
40089 if(this.dialCodeHolder) {
40090 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40095 setValue : function(v)
40097 var d = this.getDialCode(v);
40099 //invalid dial code
40100 if(v.length == 0 || !d || d.length == 0) {
40102 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40103 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40109 this.setFlagClass(this.dialCodeMapping[d].iso2);
40110 this.setDialCode(d);
40111 this.inputEl().dom.value = v.replace('+'+d,'');
40112 this.hiddenEl().dom.value = this.getValue();
40117 getDialCode : function(v = '')
40119 if (v.length == 0) {
40120 return this.dialCodeHolder.dom.value;
40124 if (v.charAt(0) != "+") {
40127 var numericChars = "";
40128 for (var i = 1; i < v.length; i++) {
40129 var c = v.charAt(i);
40132 if (this.dialCodeMapping[numericChars]) {
40133 dialCode = v.substr(1, i);
40135 if (numericChars.length == 4) {
40145 this.setValue(this.defaultDialCode);
40149 hiddenEl : function()
40151 return this.el.select('input.hidden-tel-input',true).first();
40154 onKeyUp : function(e){
40156 var k = e.getKey();
40157 var c = e.getCharCode();
40160 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40161 this.allowed.indexOf(String.fromCharCode(c)) === -1
40166 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40169 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40173 this.setValue(this.getValue());
40178 * @class Roo.bootstrap.MoneyField
40179 * @extends Roo.bootstrap.ComboBox
40180 * Bootstrap MoneyField class
40183 * Create a new MoneyField.
40184 * @param {Object} config Configuration options
40187 Roo.bootstrap.MoneyField = function(config) {
40189 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40193 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40196 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40198 allowDecimals : true,
40200 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40202 decimalSeparator : ".",
40204 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40206 decimalPrecision : 0,
40208 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40210 allowNegative : true,
40212 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40214 minValue : Number.NEGATIVE_INFINITY,
40216 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40218 maxValue : Number.MAX_VALUE,
40220 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40222 minText : "The minimum value for this field is {0}",
40224 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40226 maxText : "The maximum value for this field is {0}",
40228 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40229 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40231 nanText : "{0} is not a valid number",
40233 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40237 * @cfg {String} defaults currency of the MoneyField
40238 * value should be in lkey
40240 defaultCurrency : false,
40242 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40244 thousandsDelimiter : false,
40254 getAutoCreate : function()
40256 var align = this.labelAlign || this.parentLabelAlign();
40268 cls : 'form-control roo-money-amount-input',
40269 autocomplete: 'new-password'
40272 var hiddenInput = {
40276 cls: 'hidden-number-input'
40280 hiddenInput.name = this.name;
40283 if (this.disabled) {
40284 input.disabled = true;
40287 var clg = 12 - this.inputlg;
40288 var cmd = 12 - this.inputmd;
40289 var csm = 12 - this.inputsm;
40290 var cxs = 12 - this.inputxs;
40294 cls : 'row roo-money-field',
40298 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40302 cls: 'roo-select2-container input-group',
40306 cls : 'form-control roo-money-currency-input',
40307 autocomplete: 'new-password',
40309 name : this.currencyName
40313 cls : 'input-group-addon',
40327 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40331 cls: this.hasFeedback ? 'has-feedback' : '',
40342 if (this.fieldLabel.length) {
40345 tooltip: 'This field is required'
40351 cls: 'control-label',
40357 html: this.fieldLabel
40360 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40366 if(this.indicatorpos == 'right') {
40367 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40374 if(align == 'left') {
40382 if(this.labelWidth > 12){
40383 label.style = "width: " + this.labelWidth + 'px';
40385 if(this.labelWidth < 13 && this.labelmd == 0){
40386 this.labelmd = this.labelWidth;
40388 if(this.labellg > 0){
40389 label.cls += ' col-lg-' + this.labellg;
40390 input.cls += ' col-lg-' + (12 - this.labellg);
40392 if(this.labelmd > 0){
40393 label.cls += ' col-md-' + this.labelmd;
40394 container.cls += ' col-md-' + (12 - this.labelmd);
40396 if(this.labelsm > 0){
40397 label.cls += ' col-sm-' + this.labelsm;
40398 container.cls += ' col-sm-' + (12 - this.labelsm);
40400 if(this.labelxs > 0){
40401 label.cls += ' col-xs-' + this.labelxs;
40402 container.cls += ' col-xs-' + (12 - this.labelxs);
40413 var settings = this;
40415 ['xs','sm','md','lg'].map(function(size){
40416 if (settings[size]) {
40417 cfg.cls += ' col-' + size + '-' + settings[size];
40424 initEvents : function()
40426 this.indicator = this.indicatorEl();
40428 this.initCurrencyEvent();
40430 this.initNumberEvent();
40433 initCurrencyEvent : function()
40436 throw "can not find store for combo";
40439 this.store = Roo.factory(this.store, Roo.data);
40440 this.store.parent = this;
40444 this.triggerEl = this.el.select('.input-group-addon', true).first();
40446 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40451 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40452 _this.list.setWidth(lw);
40455 this.list.on('mouseover', this.onViewOver, this);
40456 this.list.on('mousemove', this.onViewMove, this);
40457 this.list.on('scroll', this.onViewScroll, this);
40460 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40463 this.view = new Roo.View(this.list, this.tpl, {
40464 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40467 this.view.on('click', this.onViewClick, this);
40469 this.store.on('beforeload', this.onBeforeLoad, this);
40470 this.store.on('load', this.onLoad, this);
40471 this.store.on('loadexception', this.onLoadException, this);
40473 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40474 "up" : function(e){
40475 this.inKeyMode = true;
40479 "down" : function(e){
40480 if(!this.isExpanded()){
40481 this.onTriggerClick();
40483 this.inKeyMode = true;
40488 "enter" : function(e){
40491 if(this.fireEvent("specialkey", this, e)){
40492 this.onViewClick(false);
40498 "esc" : function(e){
40502 "tab" : function(e){
40505 if(this.fireEvent("specialkey", this, e)){
40506 this.onViewClick(false);
40514 doRelay : function(foo, bar, hname){
40515 if(hname == 'down' || this.scope.isExpanded()){
40516 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40524 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40528 initNumberEvent : function(e)
40530 this.inputEl().on("keydown" , this.fireKey, this);
40531 this.inputEl().on("focus", this.onFocus, this);
40532 this.inputEl().on("blur", this.onBlur, this);
40534 this.inputEl().relayEvent('keyup', this);
40536 if(this.indicator){
40537 this.indicator.addClass('invisible');
40540 this.originalValue = this.getValue();
40542 if(this.validationEvent == 'keyup'){
40543 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40544 this.inputEl().on('keyup', this.filterValidation, this);
40546 else if(this.validationEvent !== false){
40547 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40550 if(this.selectOnFocus){
40551 this.on("focus", this.preFocus, this);
40554 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40555 this.inputEl().on("keypress", this.filterKeys, this);
40557 this.inputEl().relayEvent('keypress', this);
40560 var allowed = "0123456789";
40562 if(this.allowDecimals){
40563 allowed += this.decimalSeparator;
40566 if(this.allowNegative){
40570 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40572 var keyPress = function(e){
40574 var k = e.getKey();
40576 var c = e.getCharCode();
40579 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40580 allowed.indexOf(String.fromCharCode(c)) === -1
40586 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40590 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40595 this.inputEl().on("keypress", keyPress, this);
40599 onTriggerClick : function(e)
40606 this.loadNext = false;
40608 if(this.isExpanded()){
40613 this.hasFocus = true;
40615 if(this.triggerAction == 'all') {
40616 this.doQuery(this.allQuery, true);
40620 this.doQuery(this.getRawValue());
40623 getCurrency : function()
40625 var v = this.currencyEl().getValue();
40630 restrictHeight : function()
40632 this.list.alignTo(this.currencyEl(), this.listAlign);
40633 this.list.alignTo(this.currencyEl(), this.listAlign);
40636 onViewClick : function(view, doFocus, el, e)
40638 var index = this.view.getSelectedIndexes()[0];
40640 var r = this.store.getAt(index);
40643 this.onSelect(r, index);
40647 onSelect : function(record, index){
40649 if(this.fireEvent('beforeselect', this, record, index) !== false){
40651 this.setFromCurrencyData(index > -1 ? record.data : false);
40655 this.fireEvent('select', this, record, index);
40659 setFromCurrencyData : function(o)
40663 this.lastCurrency = o;
40665 if (this.currencyField) {
40666 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40668 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40671 this.lastSelectionText = currency;
40673 //setting default currency
40674 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40675 this.setCurrency(this.defaultCurrency);
40679 this.setCurrency(currency);
40682 setFromData : function(o)
40686 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40688 this.setFromCurrencyData(c);
40693 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40695 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40698 this.setValue(value);
40702 setCurrency : function(v)
40704 this.currencyValue = v;
40707 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40712 setValue : function(v)
40714 v = this.fixPrecision(v);
40716 v = String(v).replace(".", this.decimalSeparator);
40722 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40724 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40725 this.thousandsDelimiter || ','
40728 if(this.allowBlank && !v) {
40729 this.inputEl().dom.value = '';
40736 getRawValue : function()
40738 var v = this.inputEl().getValue();
40743 getValue : function()
40745 return this.fixPrecision(this.parseValue(this.getRawValue()));
40748 parseValue : function(value)
40750 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40751 return isNaN(value) ? '' : value;
40754 fixPrecision : function(value)
40756 var nan = isNaN(value);
40758 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40759 return nan ? '' : value;
40762 return parseFloat(value).toFixed(this.decimalPrecision);
40765 decimalPrecisionFcn : function(v)
40767 return Math.floor(v);
40770 validateValue : function(value)
40772 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40776 var num = this.parseValue(value);
40779 this.markInvalid(String.format(this.nanText, value));
40783 if(num < this.minValue){
40784 this.markInvalid(String.format(this.minText, this.minValue));
40788 if(num > this.maxValue){
40789 this.markInvalid(String.format(this.maxText, this.maxValue));
40796 validate : function()
40798 if(this.disabled || this.allowBlank){
40803 var currency = this.getCurrency();
40805 if(this.validateValue(this.getRawValue()) && currency.length){
40810 this.markInvalid();
40814 getName: function()
40819 beforeBlur : function()
40825 var v = this.parseValue(this.getRawValue());
40832 onBlur : function()
40836 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40837 //this.el.removeClass(this.focusClass);
40840 this.hasFocus = false;
40842 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40846 var v = this.getValue();
40848 if(String(v) !== String(this.startValue)){
40849 this.fireEvent('change', this, v, this.startValue);
40852 this.fireEvent("blur", this);
40855 inputEl : function()
40857 return this.el.select('.roo-money-amount-input', true).first();
40860 currencyEl : function()
40862 return this.el.select('.roo-money-currency-input', true).first();
40865 hiddenEl : function()
40867 return this.el.select('input.hidden-number-input',true).first();