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()
6962 var header = this.renderHeader();
6963 var table = this.el.select('table', true).first();
6965 this.mainHead.remove();
6966 this.mainHead = table.createChild(header, this.mainBody, false);
6969 onHiddenChange : function(colModel, colIndex, hidden)
6971 var thSelector = 'roo-bootstrap-thead-col-' + colIndex;
6972 var tdSelector = 'roo-bootstrap-tbody-col-' + colIndex;
6974 this.CSS.updateRule(thSelector, "display", "");
6975 this.CSS.updateRule(tdSelector, "display", "");
6978 this.CSS.updateRule(thSelector, "display", "none");
6979 this.CSS.updateRule(tdSelector, "display", "none");
6982 this.onHeaderChange();
6999 * @class Roo.bootstrap.TableCell
7000 * @extends Roo.bootstrap.Component
7001 * Bootstrap TableCell class
7002 * @cfg {String} html cell contain text
7003 * @cfg {String} cls cell class
7004 * @cfg {String} tag cell tag (td|th) default td
7005 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7006 * @cfg {String} align Aligns the content in a cell
7007 * @cfg {String} axis Categorizes cells
7008 * @cfg {String} bgcolor Specifies the background color of a cell
7009 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7010 * @cfg {Number} colspan Specifies the number of columns a cell should span
7011 * @cfg {String} headers Specifies one or more header cells a cell is related to
7012 * @cfg {Number} height Sets the height of a cell
7013 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7014 * @cfg {Number} rowspan Sets the number of rows a cell should span
7015 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7016 * @cfg {String} valign Vertical aligns the content in a cell
7017 * @cfg {Number} width Specifies the width of a cell
7020 * Create a new TableCell
7021 * @param {Object} config The config object
7024 Roo.bootstrap.TableCell = function(config){
7025 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7028 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7048 getAutoCreate : function(){
7049 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7069 cfg.align=this.align
7075 cfg.bgcolor=this.bgcolor
7078 cfg.charoff=this.charoff
7081 cfg.colspan=this.colspan
7084 cfg.headers=this.headers
7087 cfg.height=this.height
7090 cfg.nowrap=this.nowrap
7093 cfg.rowspan=this.rowspan
7096 cfg.scope=this.scope
7099 cfg.valign=this.valign
7102 cfg.width=this.width
7121 * @class Roo.bootstrap.TableRow
7122 * @extends Roo.bootstrap.Component
7123 * Bootstrap TableRow class
7124 * @cfg {String} cls row class
7125 * @cfg {String} align Aligns the content in a table row
7126 * @cfg {String} bgcolor Specifies a background color for a table row
7127 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7128 * @cfg {String} valign Vertical aligns the content in a table row
7131 * Create a new TableRow
7132 * @param {Object} config The config object
7135 Roo.bootstrap.TableRow = function(config){
7136 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7139 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7147 getAutoCreate : function(){
7148 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7158 cfg.align = this.align;
7161 cfg.bgcolor = this.bgcolor;
7164 cfg.charoff = this.charoff;
7167 cfg.valign = this.valign;
7185 * @class Roo.bootstrap.TableBody
7186 * @extends Roo.bootstrap.Component
7187 * Bootstrap TableBody class
7188 * @cfg {String} cls element class
7189 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7190 * @cfg {String} align Aligns the content inside the element
7191 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7192 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7195 * Create a new TableBody
7196 * @param {Object} config The config object
7199 Roo.bootstrap.TableBody = function(config){
7200 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7203 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7211 getAutoCreate : function(){
7212 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7226 cfg.align = this.align;
7229 cfg.charoff = this.charoff;
7232 cfg.valign = this.valign;
7239 // initEvents : function()
7246 // this.store = Roo.factory(this.store, Roo.data);
7247 // this.store.on('load', this.onLoad, this);
7249 // this.store.load();
7253 // onLoad: function ()
7255 // this.fireEvent('load', this);
7265 * Ext JS Library 1.1.1
7266 * Copyright(c) 2006-2007, Ext JS, LLC.
7268 * Originally Released Under LGPL - original licence link has changed is not relivant.
7271 * <script type="text/javascript">
7274 // as we use this in bootstrap.
7275 Roo.namespace('Roo.form');
7277 * @class Roo.form.Action
7278 * Internal Class used to handle form actions
7280 * @param {Roo.form.BasicForm} el The form element or its id
7281 * @param {Object} config Configuration options
7286 // define the action interface
7287 Roo.form.Action = function(form, options){
7289 this.options = options || {};
7292 * Client Validation Failed
7295 Roo.form.Action.CLIENT_INVALID = 'client';
7297 * Server Validation Failed
7300 Roo.form.Action.SERVER_INVALID = 'server';
7302 * Connect to Server Failed
7305 Roo.form.Action.CONNECT_FAILURE = 'connect';
7307 * Reading Data from Server Failed
7310 Roo.form.Action.LOAD_FAILURE = 'load';
7312 Roo.form.Action.prototype = {
7314 failureType : undefined,
7315 response : undefined,
7319 run : function(options){
7324 success : function(response){
7329 handleResponse : function(response){
7333 // default connection failure
7334 failure : function(response){
7336 this.response = response;
7337 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7338 this.form.afterAction(this, false);
7341 processResponse : function(response){
7342 this.response = response;
7343 if(!response.responseText){
7346 this.result = this.handleResponse(response);
7350 // utility functions used internally
7351 getUrl : function(appendParams){
7352 var url = this.options.url || this.form.url || this.form.el.dom.action;
7354 var p = this.getParams();
7356 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7362 getMethod : function(){
7363 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7366 getParams : function(){
7367 var bp = this.form.baseParams;
7368 var p = this.options.params;
7370 if(typeof p == "object"){
7371 p = Roo.urlEncode(Roo.applyIf(p, bp));
7372 }else if(typeof p == 'string' && bp){
7373 p += '&' + Roo.urlEncode(bp);
7376 p = Roo.urlEncode(bp);
7381 createCallback : function(){
7383 success: this.success,
7384 failure: this.failure,
7386 timeout: (this.form.timeout*1000),
7387 upload: this.form.fileUpload ? this.success : undefined
7392 Roo.form.Action.Submit = function(form, options){
7393 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7396 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7399 haveProgress : false,
7400 uploadComplete : false,
7402 // uploadProgress indicator.
7403 uploadProgress : function()
7405 if (!this.form.progressUrl) {
7409 if (!this.haveProgress) {
7410 Roo.MessageBox.progress("Uploading", "Uploading");
7412 if (this.uploadComplete) {
7413 Roo.MessageBox.hide();
7417 this.haveProgress = true;
7419 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7421 var c = new Roo.data.Connection();
7423 url : this.form.progressUrl,
7428 success : function(req){
7429 //console.log(data);
7433 rdata = Roo.decode(req.responseText)
7435 Roo.log("Invalid data from server..");
7439 if (!rdata || !rdata.success) {
7441 Roo.MessageBox.alert(Roo.encode(rdata));
7444 var data = rdata.data;
7446 if (this.uploadComplete) {
7447 Roo.MessageBox.hide();
7452 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7453 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7456 this.uploadProgress.defer(2000,this);
7459 failure: function(data) {
7460 Roo.log('progress url failed ');
7471 // run get Values on the form, so it syncs any secondary forms.
7472 this.form.getValues();
7474 var o = this.options;
7475 var method = this.getMethod();
7476 var isPost = method == 'POST';
7477 if(o.clientValidation === false || this.form.isValid()){
7479 if (this.form.progressUrl) {
7480 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7481 (new Date() * 1) + '' + Math.random());
7486 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7487 form:this.form.el.dom,
7488 url:this.getUrl(!isPost),
7490 params:isPost ? this.getParams() : null,
7491 isUpload: this.form.fileUpload
7494 this.uploadProgress();
7496 }else if (o.clientValidation !== false){ // client validation failed
7497 this.failureType = Roo.form.Action.CLIENT_INVALID;
7498 this.form.afterAction(this, false);
7502 success : function(response)
7504 this.uploadComplete= true;
7505 if (this.haveProgress) {
7506 Roo.MessageBox.hide();
7510 var result = this.processResponse(response);
7511 if(result === true || result.success){
7512 this.form.afterAction(this, true);
7516 this.form.markInvalid(result.errors);
7517 this.failureType = Roo.form.Action.SERVER_INVALID;
7519 this.form.afterAction(this, false);
7521 failure : function(response)
7523 this.uploadComplete= true;
7524 if (this.haveProgress) {
7525 Roo.MessageBox.hide();
7528 this.response = response;
7529 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7530 this.form.afterAction(this, false);
7533 handleResponse : function(response){
7534 if(this.form.errorReader){
7535 var rs = this.form.errorReader.read(response);
7538 for(var i = 0, len = rs.records.length; i < len; i++) {
7539 var r = rs.records[i];
7543 if(errors.length < 1){
7547 success : rs.success,
7553 ret = Roo.decode(response.responseText);
7557 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7567 Roo.form.Action.Load = function(form, options){
7568 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7569 this.reader = this.form.reader;
7572 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7577 Roo.Ajax.request(Roo.apply(
7578 this.createCallback(), {
7579 method:this.getMethod(),
7580 url:this.getUrl(false),
7581 params:this.getParams()
7585 success : function(response){
7587 var result = this.processResponse(response);
7588 if(result === true || !result.success || !result.data){
7589 this.failureType = Roo.form.Action.LOAD_FAILURE;
7590 this.form.afterAction(this, false);
7593 this.form.clearInvalid();
7594 this.form.setValues(result.data);
7595 this.form.afterAction(this, true);
7598 handleResponse : function(response){
7599 if(this.form.reader){
7600 var rs = this.form.reader.read(response);
7601 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7603 success : rs.success,
7607 return Roo.decode(response.responseText);
7611 Roo.form.Action.ACTION_TYPES = {
7612 'load' : Roo.form.Action.Load,
7613 'submit' : Roo.form.Action.Submit
7622 * @class Roo.bootstrap.Form
7623 * @extends Roo.bootstrap.Component
7624 * Bootstrap Form class
7625 * @cfg {String} method GET | POST (default POST)
7626 * @cfg {String} labelAlign top | left (default top)
7627 * @cfg {String} align left | right - for navbars
7628 * @cfg {Boolean} loadMask load mask when submit (default true)
7633 * @param {Object} config The config object
7637 Roo.bootstrap.Form = function(config){
7639 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7641 Roo.bootstrap.Form.popover.apply();
7645 * @event clientvalidation
7646 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7647 * @param {Form} this
7648 * @param {Boolean} valid true if the form has passed client-side validation
7650 clientvalidation: true,
7652 * @event beforeaction
7653 * Fires before any action is performed. Return false to cancel the action.
7654 * @param {Form} this
7655 * @param {Action} action The action to be performed
7659 * @event actionfailed
7660 * Fires when an action fails.
7661 * @param {Form} this
7662 * @param {Action} action The action that failed
7664 actionfailed : true,
7666 * @event actioncomplete
7667 * Fires when an action is completed.
7668 * @param {Form} this
7669 * @param {Action} action The action that completed
7671 actioncomplete : true
7675 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7678 * @cfg {String} method
7679 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7684 * The URL to use for form actions if one isn't supplied in the action options.
7687 * @cfg {Boolean} fileUpload
7688 * Set to true if this form is a file upload.
7692 * @cfg {Object} baseParams
7693 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7697 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7701 * @cfg {Sting} align (left|right) for navbar forms
7706 activeAction : null,
7709 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7710 * element by passing it or its id or mask the form itself by passing in true.
7713 waitMsgTarget : false,
7718 * @cfg {Boolean} errorMask (true|false) default false
7723 * @cfg {Number} maskOffset Default 100
7728 * @cfg {Boolean} maskBody
7732 getAutoCreate : function(){
7736 method : this.method || 'POST',
7737 id : this.id || Roo.id(),
7740 if (this.parent().xtype.match(/^Nav/)) {
7741 cfg.cls = 'navbar-form navbar-' + this.align;
7745 if (this.labelAlign == 'left' ) {
7746 cfg.cls += ' form-horizontal';
7752 initEvents : function()
7754 this.el.on('submit', this.onSubmit, this);
7755 // this was added as random key presses on the form where triggering form submit.
7756 this.el.on('keypress', function(e) {
7757 if (e.getCharCode() != 13) {
7760 // we might need to allow it for textareas.. and some other items.
7761 // check e.getTarget().
7763 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7767 Roo.log("keypress blocked");
7775 onSubmit : function(e){
7780 * Returns true if client-side validation on the form is successful.
7783 isValid : function(){
7784 var items = this.getItems();
7788 items.each(function(f){
7794 if(!target && f.el.isVisible(true)){
7800 if(this.errorMask && !valid){
7801 Roo.bootstrap.Form.popover.mask(this, target);
7808 * Returns true if any fields in this form have changed since their original load.
7811 isDirty : function(){
7813 var items = this.getItems();
7814 items.each(function(f){
7824 * Performs a predefined action (submit or load) or custom actions you define on this form.
7825 * @param {String} actionName The name of the action type
7826 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
7827 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7828 * accept other config options):
7830 Property Type Description
7831 ---------------- --------------- ----------------------------------------------------------------------------------
7832 url String The url for the action (defaults to the form's url)
7833 method String The form method to use (defaults to the form's method, or POST if not defined)
7834 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
7835 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
7836 validate the form on the client (defaults to false)
7838 * @return {BasicForm} this
7840 doAction : function(action, options){
7841 if(typeof action == 'string'){
7842 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7844 if(this.fireEvent('beforeaction', this, action) !== false){
7845 this.beforeAction(action);
7846 action.run.defer(100, action);
7852 beforeAction : function(action){
7853 var o = action.options;
7858 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7860 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7863 // not really supported yet.. ??
7865 //if(this.waitMsgTarget === true){
7866 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7867 //}else if(this.waitMsgTarget){
7868 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7869 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7871 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7877 afterAction : function(action, success){
7878 this.activeAction = null;
7879 var o = action.options;
7884 Roo.get(document.body).unmask();
7890 //if(this.waitMsgTarget === true){
7891 // this.el.unmask();
7892 //}else if(this.waitMsgTarget){
7893 // this.waitMsgTarget.unmask();
7895 // Roo.MessageBox.updateProgress(1);
7896 // Roo.MessageBox.hide();
7903 Roo.callback(o.success, o.scope, [this, action]);
7904 this.fireEvent('actioncomplete', this, action);
7908 // failure condition..
7909 // we have a scenario where updates need confirming.
7910 // eg. if a locking scenario exists..
7911 // we look for { errors : { needs_confirm : true }} in the response.
7913 (typeof(action.result) != 'undefined') &&
7914 (typeof(action.result.errors) != 'undefined') &&
7915 (typeof(action.result.errors.needs_confirm) != 'undefined')
7918 Roo.log("not supported yet");
7921 Roo.MessageBox.confirm(
7922 "Change requires confirmation",
7923 action.result.errorMsg,
7928 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7938 Roo.callback(o.failure, o.scope, [this, action]);
7939 // show an error message if no failed handler is set..
7940 if (!this.hasListener('actionfailed')) {
7941 Roo.log("need to add dialog support");
7943 Roo.MessageBox.alert("Error",
7944 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7945 action.result.errorMsg :
7946 "Saving Failed, please check your entries or try again"
7951 this.fireEvent('actionfailed', this, action);
7956 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7957 * @param {String} id The value to search for
7960 findField : function(id){
7961 var items = this.getItems();
7962 var field = items.get(id);
7964 items.each(function(f){
7965 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7972 return field || null;
7975 * Mark fields in this form invalid in bulk.
7976 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7977 * @return {BasicForm} this
7979 markInvalid : function(errors){
7980 if(errors instanceof Array){
7981 for(var i = 0, len = errors.length; i < len; i++){
7982 var fieldError = errors[i];
7983 var f = this.findField(fieldError.id);
7985 f.markInvalid(fieldError.msg);
7991 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7992 field.markInvalid(errors[id]);
7996 //Roo.each(this.childForms || [], function (f) {
7997 // f.markInvalid(errors);
8004 * Set values for fields in this form in bulk.
8005 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8006 * @return {BasicForm} this
8008 setValues : function(values){
8009 if(values instanceof Array){ // array of objects
8010 for(var i = 0, len = values.length; i < len; i++){
8012 var f = this.findField(v.id);
8014 f.setValue(v.value);
8015 if(this.trackResetOnLoad){
8016 f.originalValue = f.getValue();
8020 }else{ // object hash
8023 if(typeof values[id] != 'function' && (field = this.findField(id))){
8025 if (field.setFromData &&
8027 field.displayField &&
8028 // combos' with local stores can
8029 // be queried via setValue()
8030 // to set their value..
8031 (field.store && !field.store.isLocal)
8035 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8036 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8037 field.setFromData(sd);
8039 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8041 field.setFromData(values);
8044 field.setValue(values[id]);
8048 if(this.trackResetOnLoad){
8049 field.originalValue = field.getValue();
8055 //Roo.each(this.childForms || [], function (f) {
8056 // f.setValues(values);
8063 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8064 * they are returned as an array.
8065 * @param {Boolean} asString
8068 getValues : function(asString){
8069 //if (this.childForms) {
8070 // copy values from the child forms
8071 // Roo.each(this.childForms, function (f) {
8072 // this.setValues(f.getValues());
8078 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8079 if(asString === true){
8082 return Roo.urlDecode(fs);
8086 * Returns the fields in this form as an object with key/value pairs.
8087 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8090 getFieldValues : function(with_hidden)
8092 var items = this.getItems();
8094 items.each(function(f){
8100 var v = f.getValue();
8102 if (f.inputType =='radio') {
8103 if (typeof(ret[f.getName()]) == 'undefined') {
8104 ret[f.getName()] = ''; // empty..
8107 if (!f.el.dom.checked) {
8115 if(f.xtype == 'MoneyField'){
8116 ret[f.currencyName] = f.getCurrency();
8119 // not sure if this supported any more..
8120 if ((typeof(v) == 'object') && f.getRawValue) {
8121 v = f.getRawValue() ; // dates..
8123 // combo boxes where name != hiddenName...
8124 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8125 ret[f.name] = f.getRawValue();
8127 ret[f.getName()] = v;
8134 * Clears all invalid messages in this form.
8135 * @return {BasicForm} this
8137 clearInvalid : function(){
8138 var items = this.getItems();
8140 items.each(function(f){
8149 * @return {BasicForm} this
8152 var items = this.getItems();
8153 items.each(function(f){
8157 Roo.each(this.childForms || [], function (f) {
8165 getItems : function()
8167 var r=new Roo.util.MixedCollection(false, function(o){
8168 return o.id || (o.id = Roo.id());
8170 var iter = function(el) {
8177 Roo.each(el.items,function(e) {
8186 hideFields : function(items)
8188 Roo.each(items, function(i){
8190 var f = this.findField(i);
8196 if(f.xtype == 'DateField'){
8197 f.setVisible(false);
8206 showFields : function(items)
8208 Roo.each(items, function(i){
8210 var f = this.findField(i);
8216 if(f.xtype == 'DateField'){
8228 Roo.apply(Roo.bootstrap.Form, {
8255 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8256 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8257 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8258 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8261 this.maskEl.top.enableDisplayMode("block");
8262 this.maskEl.left.enableDisplayMode("block");
8263 this.maskEl.bottom.enableDisplayMode("block");
8264 this.maskEl.right.enableDisplayMode("block");
8266 this.toolTip = new Roo.bootstrap.Tooltip({
8267 cls : 'roo-form-error-popover',
8269 'left' : ['r-l', [-2,0], 'right'],
8270 'right' : ['l-r', [2,0], 'left'],
8271 'bottom' : ['tl-bl', [0,2], 'top'],
8272 'top' : [ 'bl-tl', [0,-2], 'bottom']
8276 this.toolTip.render(Roo.get(document.body));
8278 this.toolTip.el.enableDisplayMode("block");
8280 Roo.get(document.body).on('click', function(){
8284 Roo.get(document.body).on('touchstart', function(){
8288 this.isApplied = true
8291 mask : function(form, target)
8295 this.target = target;
8297 if(!this.form.errorMask || !target.el){
8301 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8303 Roo.log(scrollable);
8305 var ot = this.target.el.calcOffsetsTo(scrollable);
8307 var scrollTo = ot[1] - this.form.maskOffset;
8309 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8311 scrollable.scrollTo('top', scrollTo);
8313 var box = this.target.el.getBox();
8315 var zIndex = Roo.bootstrap.Modal.zIndex++;
8318 this.maskEl.top.setStyle('position', 'absolute');
8319 this.maskEl.top.setStyle('z-index', zIndex);
8320 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8321 this.maskEl.top.setLeft(0);
8322 this.maskEl.top.setTop(0);
8323 this.maskEl.top.show();
8325 this.maskEl.left.setStyle('position', 'absolute');
8326 this.maskEl.left.setStyle('z-index', zIndex);
8327 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8328 this.maskEl.left.setLeft(0);
8329 this.maskEl.left.setTop(box.y - this.padding);
8330 this.maskEl.left.show();
8332 this.maskEl.bottom.setStyle('position', 'absolute');
8333 this.maskEl.bottom.setStyle('z-index', zIndex);
8334 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8335 this.maskEl.bottom.setLeft(0);
8336 this.maskEl.bottom.setTop(box.bottom + this.padding);
8337 this.maskEl.bottom.show();
8339 this.maskEl.right.setStyle('position', 'absolute');
8340 this.maskEl.right.setStyle('z-index', zIndex);
8341 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8342 this.maskEl.right.setLeft(box.right + this.padding);
8343 this.maskEl.right.setTop(box.y - this.padding);
8344 this.maskEl.right.show();
8346 this.toolTip.bindEl = this.target.el;
8348 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8350 var tip = this.target.blankText;
8352 if(this.target.getValue() !== '' ) {
8354 if (this.target.invalidText.length) {
8355 tip = this.target.invalidText;
8356 } else if (this.target.regexText.length){
8357 tip = this.target.regexText;
8361 this.toolTip.show(tip);
8363 this.intervalID = window.setInterval(function() {
8364 Roo.bootstrap.Form.popover.unmask();
8367 window.onwheel = function(){ return false;};
8369 (function(){ this.isMasked = true; }).defer(500, this);
8375 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8379 this.maskEl.top.setStyle('position', 'absolute');
8380 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8381 this.maskEl.top.hide();
8383 this.maskEl.left.setStyle('position', 'absolute');
8384 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8385 this.maskEl.left.hide();
8387 this.maskEl.bottom.setStyle('position', 'absolute');
8388 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8389 this.maskEl.bottom.hide();
8391 this.maskEl.right.setStyle('position', 'absolute');
8392 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8393 this.maskEl.right.hide();
8395 this.toolTip.hide();
8397 this.toolTip.el.hide();
8399 window.onwheel = function(){ return true;};
8401 if(this.intervalID){
8402 window.clearInterval(this.intervalID);
8403 this.intervalID = false;
8406 this.isMasked = false;
8416 * Ext JS Library 1.1.1
8417 * Copyright(c) 2006-2007, Ext JS, LLC.
8419 * Originally Released Under LGPL - original licence link has changed is not relivant.
8422 * <script type="text/javascript">
8425 * @class Roo.form.VTypes
8426 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8429 Roo.form.VTypes = function(){
8430 // closure these in so they are only created once.
8431 var alpha = /^[a-zA-Z_]+$/;
8432 var alphanum = /^[a-zA-Z0-9_]+$/;
8433 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8434 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8436 // All these messages and functions are configurable
8439 * The function used to validate email addresses
8440 * @param {String} value The email address
8442 'email' : function(v){
8443 return email.test(v);
8446 * The error text to display when the email validation function returns false
8449 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8451 * The keystroke filter mask to be applied on email input
8454 'emailMask' : /[a-z0-9_\.\-@]/i,
8457 * The function used to validate URLs
8458 * @param {String} value The URL
8460 'url' : function(v){
8464 * The error text to display when the url validation function returns false
8467 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8470 * The function used to validate alpha values
8471 * @param {String} value The value
8473 'alpha' : function(v){
8474 return alpha.test(v);
8477 * The error text to display when the alpha validation function returns false
8480 'alphaText' : 'This field should only contain letters and _',
8482 * The keystroke filter mask to be applied on alpha input
8485 'alphaMask' : /[a-z_]/i,
8488 * The function used to validate alphanumeric values
8489 * @param {String} value The value
8491 'alphanum' : function(v){
8492 return alphanum.test(v);
8495 * The error text to display when the alphanumeric validation function returns false
8498 'alphanumText' : 'This field should only contain letters, numbers and _',
8500 * The keystroke filter mask to be applied on alphanumeric input
8503 'alphanumMask' : /[a-z0-9_]/i
8513 * @class Roo.bootstrap.Input
8514 * @extends Roo.bootstrap.Component
8515 * Bootstrap Input class
8516 * @cfg {Boolean} disabled is it disabled
8517 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8518 * @cfg {String} name name of the input
8519 * @cfg {string} fieldLabel - the label associated
8520 * @cfg {string} placeholder - placeholder to put in text.
8521 * @cfg {string} before - input group add on before
8522 * @cfg {string} after - input group add on after
8523 * @cfg {string} size - (lg|sm) or leave empty..
8524 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8525 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8526 * @cfg {Number} md colspan out of 12 for computer-sized screens
8527 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8528 * @cfg {string} value default value of the input
8529 * @cfg {Number} labelWidth set the width of label
8530 * @cfg {Number} labellg set the width of label (1-12)
8531 * @cfg {Number} labelmd set the width of label (1-12)
8532 * @cfg {Number} labelsm set the width of label (1-12)
8533 * @cfg {Number} labelxs set the width of label (1-12)
8534 * @cfg {String} labelAlign (top|left)
8535 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8536 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8537 * @cfg {String} indicatorpos (left|right) default left
8539 * @cfg {String} align (left|center|right) Default left
8540 * @cfg {Boolean} forceFeedback (true|false) Default false
8543 * Create a new Input
8544 * @param {Object} config The config object
8547 Roo.bootstrap.Input = function(config){
8549 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8554 * Fires when this field receives input focus.
8555 * @param {Roo.form.Field} this
8560 * Fires when this field loses input focus.
8561 * @param {Roo.form.Field} this
8566 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8567 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8568 * @param {Roo.form.Field} this
8569 * @param {Roo.EventObject} e The event object
8574 * Fires just before the field blurs if the field value has changed.
8575 * @param {Roo.form.Field} this
8576 * @param {Mixed} newValue The new value
8577 * @param {Mixed} oldValue The original value
8582 * Fires after the field has been marked as invalid.
8583 * @param {Roo.form.Field} this
8584 * @param {String} msg The validation message
8589 * Fires after the field has been validated with no errors.
8590 * @param {Roo.form.Field} this
8595 * Fires after the key up
8596 * @param {Roo.form.Field} this
8597 * @param {Roo.EventObject} e The event Object
8603 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8605 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8606 automatic validation (defaults to "keyup").
8608 validationEvent : "keyup",
8610 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8612 validateOnBlur : true,
8614 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8616 validationDelay : 250,
8618 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8620 focusClass : "x-form-focus", // not needed???
8624 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8626 invalidClass : "has-warning",
8629 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8631 validClass : "has-success",
8634 * @cfg {Boolean} hasFeedback (true|false) default true
8639 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8641 invalidFeedbackClass : "glyphicon-warning-sign",
8644 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8646 validFeedbackClass : "glyphicon-ok",
8649 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8651 selectOnFocus : false,
8654 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8658 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8663 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8665 disableKeyFilter : false,
8668 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8672 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8676 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8678 blankText : "Please complete this mandatory field",
8681 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8685 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8687 maxLength : Number.MAX_VALUE,
8689 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8691 minLengthText : "The minimum length for this field is {0}",
8693 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8695 maxLengthText : "The maximum length for this field is {0}",
8699 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8700 * If available, this function will be called only after the basic validators all return true, and will be passed the
8701 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8705 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8706 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8707 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8711 * @cfg {String} regexText -- Depricated - use Invalid Text
8716 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8722 autocomplete: false,
8741 formatedValue : false,
8742 forceFeedback : false,
8744 indicatorpos : 'left',
8751 parentLabelAlign : function()
8754 while (parent.parent()) {
8755 parent = parent.parent();
8756 if (typeof(parent.labelAlign) !='undefined') {
8757 return parent.labelAlign;
8764 getAutoCreate : function()
8766 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8772 if(this.inputType != 'hidden'){
8773 cfg.cls = 'form-group' //input-group
8779 type : this.inputType,
8781 cls : 'form-control',
8782 placeholder : this.placeholder || '',
8783 autocomplete : this.autocomplete || 'new-password'
8787 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8790 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8791 input.maxLength = this.maxLength;
8794 if (this.disabled) {
8795 input.disabled=true;
8798 if (this.readOnly) {
8799 input.readonly=true;
8803 input.name = this.name;
8807 input.cls += ' input-' + this.size;
8811 ['xs','sm','md','lg'].map(function(size){
8812 if (settings[size]) {
8813 cfg.cls += ' col-' + size + '-' + settings[size];
8817 var inputblock = input;
8821 cls: 'glyphicon form-control-feedback'
8824 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8827 cls : 'has-feedback',
8835 if (this.before || this.after) {
8838 cls : 'input-group',
8842 if (this.before && typeof(this.before) == 'string') {
8844 inputblock.cn.push({
8846 cls : 'roo-input-before input-group-addon',
8850 if (this.before && typeof(this.before) == 'object') {
8851 this.before = Roo.factory(this.before);
8853 inputblock.cn.push({
8855 cls : 'roo-input-before input-group-' +
8856 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8860 inputblock.cn.push(input);
8862 if (this.after && typeof(this.after) == 'string') {
8863 inputblock.cn.push({
8865 cls : 'roo-input-after input-group-addon',
8869 if (this.after && typeof(this.after) == 'object') {
8870 this.after = Roo.factory(this.after);
8872 inputblock.cn.push({
8874 cls : 'roo-input-after input-group-' +
8875 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
8879 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8880 inputblock.cls += ' has-feedback';
8881 inputblock.cn.push(feedback);
8885 if (align ==='left' && this.fieldLabel.length) {
8887 cfg.cls += ' roo-form-group-label-left';
8892 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8893 tooltip : 'This field is required'
8898 cls : 'control-label',
8899 html : this.fieldLabel
8910 var labelCfg = cfg.cn[1];
8911 var contentCfg = cfg.cn[2];
8913 if(this.indicatorpos == 'right'){
8918 cls : 'control-label',
8922 html : this.fieldLabel
8926 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8927 tooltip : 'This field is required'
8940 labelCfg = cfg.cn[0];
8941 contentCfg = cfg.cn[1];
8945 if(this.labelWidth > 12){
8946 labelCfg.style = "width: " + this.labelWidth + 'px';
8949 if(this.labelWidth < 13 && this.labelmd == 0){
8950 this.labelmd = this.labelWidth;
8953 if(this.labellg > 0){
8954 labelCfg.cls += ' col-lg-' + this.labellg;
8955 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8958 if(this.labelmd > 0){
8959 labelCfg.cls += ' col-md-' + this.labelmd;
8960 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8963 if(this.labelsm > 0){
8964 labelCfg.cls += ' col-sm-' + this.labelsm;
8965 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8968 if(this.labelxs > 0){
8969 labelCfg.cls += ' col-xs-' + this.labelxs;
8970 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8974 } else if ( this.fieldLabel.length) {
8979 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8980 tooltip : 'This field is required'
8984 //cls : 'input-group-addon',
8985 html : this.fieldLabel
8993 if(this.indicatorpos == 'right'){
8998 //cls : 'input-group-addon',
8999 html : this.fieldLabel
9004 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9005 tooltip : 'This field is required'
9025 if (this.parentType === 'Navbar' && this.parent().bar) {
9026 cfg.cls += ' navbar-form';
9029 if (this.parentType === 'NavGroup') {
9030 cfg.cls += ' navbar-form';
9038 * return the real input element.
9040 inputEl: function ()
9042 return this.el.select('input.form-control',true).first();
9045 tooltipEl : function()
9047 return this.inputEl();
9050 indicatorEl : function()
9052 var indicator = this.el.select('i.roo-required-indicator',true).first();
9062 setDisabled : function(v)
9064 var i = this.inputEl().dom;
9066 i.removeAttribute('disabled');
9070 i.setAttribute('disabled','true');
9072 initEvents : function()
9075 this.inputEl().on("keydown" , this.fireKey, this);
9076 this.inputEl().on("focus", this.onFocus, this);
9077 this.inputEl().on("blur", this.onBlur, this);
9079 this.inputEl().relayEvent('keyup', this);
9081 this.indicator = this.indicatorEl();
9084 this.indicator.addClass('invisible');
9087 // reference to original value for reset
9088 this.originalValue = this.getValue();
9089 //Roo.form.TextField.superclass.initEvents.call(this);
9090 if(this.validationEvent == 'keyup'){
9091 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9092 this.inputEl().on('keyup', this.filterValidation, this);
9094 else if(this.validationEvent !== false){
9095 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9098 if(this.selectOnFocus){
9099 this.on("focus", this.preFocus, this);
9102 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9103 this.inputEl().on("keypress", this.filterKeys, this);
9105 this.inputEl().relayEvent('keypress', this);
9108 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9109 this.el.on("click", this.autoSize, this);
9112 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9113 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9116 if (typeof(this.before) == 'object') {
9117 this.before.render(this.el.select('.roo-input-before',true).first());
9119 if (typeof(this.after) == 'object') {
9120 this.after.render(this.el.select('.roo-input-after',true).first());
9125 filterValidation : function(e){
9126 if(!e.isNavKeyPress()){
9127 this.validationTask.delay(this.validationDelay);
9131 * Validates the field value
9132 * @return {Boolean} True if the value is valid, else false
9134 validate : function(){
9135 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9136 if(this.disabled || this.validateValue(this.getRawValue())){
9147 * Validates a value according to the field's validation rules and marks the field as invalid
9148 * if the validation fails
9149 * @param {Mixed} value The value to validate
9150 * @return {Boolean} True if the value is valid, else false
9152 validateValue : function(value)
9154 if(this.getVisibilityEl().hasClass('hidden')){
9158 if(value.length < 1) { // if it's blank
9159 if(this.allowBlank){
9165 if(value.length < this.minLength){
9168 if(value.length > this.maxLength){
9172 var vt = Roo.form.VTypes;
9173 if(!vt[this.vtype](value, this)){
9177 if(typeof this.validator == "function"){
9178 var msg = this.validator(value);
9182 if (typeof(msg) == 'string') {
9183 this.invalidText = msg;
9187 if(this.regex && !this.regex.test(value)){
9195 fireKey : function(e){
9196 //Roo.log('field ' + e.getKey());
9197 if(e.isNavKeyPress()){
9198 this.fireEvent("specialkey", this, e);
9201 focus : function (selectText){
9203 this.inputEl().focus();
9204 if(selectText === true){
9205 this.inputEl().dom.select();
9211 onFocus : function(){
9212 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9213 // this.el.addClass(this.focusClass);
9216 this.hasFocus = true;
9217 this.startValue = this.getValue();
9218 this.fireEvent("focus", this);
9222 beforeBlur : Roo.emptyFn,
9226 onBlur : function(){
9228 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9229 //this.el.removeClass(this.focusClass);
9231 this.hasFocus = false;
9232 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9235 var v = this.getValue();
9236 if(String(v) !== String(this.startValue)){
9237 this.fireEvent('change', this, v, this.startValue);
9239 this.fireEvent("blur", this);
9243 * Resets the current field value to the originally loaded value and clears any validation messages
9246 this.setValue(this.originalValue);
9250 * Returns the name of the field
9251 * @return {Mixed} name The name field
9253 getName: function(){
9257 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9258 * @return {Mixed} value The field value
9260 getValue : function(){
9262 var v = this.inputEl().getValue();
9267 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9268 * @return {Mixed} value The field value
9270 getRawValue : function(){
9271 var v = this.inputEl().getValue();
9277 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9278 * @param {Mixed} value The value to set
9280 setRawValue : function(v){
9281 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9284 selectText : function(start, end){
9285 var v = this.getRawValue();
9287 start = start === undefined ? 0 : start;
9288 end = end === undefined ? v.length : end;
9289 var d = this.inputEl().dom;
9290 if(d.setSelectionRange){
9291 d.setSelectionRange(start, end);
9292 }else if(d.createTextRange){
9293 var range = d.createTextRange();
9294 range.moveStart("character", start);
9295 range.moveEnd("character", v.length-end);
9302 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9303 * @param {Mixed} value The value to set
9305 setValue : function(v){
9308 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9314 processValue : function(value){
9315 if(this.stripCharsRe){
9316 var newValue = value.replace(this.stripCharsRe, '');
9317 if(newValue !== value){
9318 this.setRawValue(newValue);
9325 preFocus : function(){
9327 if(this.selectOnFocus){
9328 this.inputEl().dom.select();
9331 filterKeys : function(e){
9333 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9336 var c = e.getCharCode(), cc = String.fromCharCode(c);
9337 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9340 if(!this.maskRe.test(cc)){
9345 * Clear any invalid styles/messages for this field
9347 clearInvalid : function(){
9349 if(!this.el || this.preventMark){ // not rendered
9354 this.el.removeClass(this.invalidClass);
9356 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9358 var feedback = this.el.select('.form-control-feedback', true).first();
9361 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9366 this.fireEvent('valid', this);
9370 * Mark this field as valid
9372 markValid : function()
9374 if(!this.el || this.preventMark){ // not rendered...
9378 this.el.removeClass([this.invalidClass, this.validClass]);
9380 var feedback = this.el.select('.form-control-feedback', true).first();
9383 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9387 this.indicator.removeClass('visible');
9388 this.indicator.addClass('invisible');
9395 if(this.allowBlank && !this.getRawValue().length){
9399 this.el.addClass(this.validClass);
9401 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9403 var feedback = this.el.select('.form-control-feedback', true).first();
9406 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9407 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9412 this.fireEvent('valid', this);
9416 * Mark this field as invalid
9417 * @param {String} msg The validation message
9419 markInvalid : function(msg)
9421 if(!this.el || this.preventMark){ // not rendered
9425 this.el.removeClass([this.invalidClass, this.validClass]);
9427 var feedback = this.el.select('.form-control-feedback', true).first();
9430 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9437 if(this.allowBlank && !this.getRawValue().length){
9442 this.indicator.removeClass('invisible');
9443 this.indicator.addClass('visible');
9446 this.el.addClass(this.invalidClass);
9448 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9450 var feedback = this.el.select('.form-control-feedback', true).first();
9453 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9455 if(this.getValue().length || this.forceFeedback){
9456 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9463 this.fireEvent('invalid', this, msg);
9466 SafariOnKeyDown : function(event)
9468 // this is a workaround for a password hang bug on chrome/ webkit.
9469 if (this.inputEl().dom.type != 'password') {
9473 var isSelectAll = false;
9475 if(this.inputEl().dom.selectionEnd > 0){
9476 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9478 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9479 event.preventDefault();
9484 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9486 event.preventDefault();
9487 // this is very hacky as keydown always get's upper case.
9489 var cc = String.fromCharCode(event.getCharCode());
9490 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9494 adjustWidth : function(tag, w){
9495 tag = tag.toLowerCase();
9496 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9497 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9501 if(tag == 'textarea'){
9504 }else if(Roo.isOpera){
9508 if(tag == 'textarea'){
9516 setFieldLabel : function(v)
9523 var ar = this.el.select('label > span',true);
9525 if (ar.elements.length) {
9526 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9527 this.fieldLabel = v;
9531 var br = this.el.select('label',true);
9533 if(br.elements.length) {
9534 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9535 this.fieldLabel = v;
9539 Roo.log('Cannot Found any of label > span || label in input');
9543 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9544 this.fieldLabel = v;
9559 * @class Roo.bootstrap.TextArea
9560 * @extends Roo.bootstrap.Input
9561 * Bootstrap TextArea class
9562 * @cfg {Number} cols Specifies the visible width of a text area
9563 * @cfg {Number} rows Specifies the visible number of lines in a text area
9564 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9565 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9566 * @cfg {string} html text
9569 * Create a new TextArea
9570 * @param {Object} config The config object
9573 Roo.bootstrap.TextArea = function(config){
9574 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9578 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9588 getAutoCreate : function(){
9590 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9596 if(this.inputType != 'hidden'){
9597 cfg.cls = 'form-group' //input-group
9605 value : this.value || '',
9606 html: this.html || '',
9607 cls : 'form-control',
9608 placeholder : this.placeholder || ''
9612 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9613 input.maxLength = this.maxLength;
9617 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9621 input.cols = this.cols;
9624 if (this.readOnly) {
9625 input.readonly = true;
9629 input.name = this.name;
9633 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9637 ['xs','sm','md','lg'].map(function(size){
9638 if (settings[size]) {
9639 cfg.cls += ' col-' + size + '-' + settings[size];
9643 var inputblock = input;
9645 if(this.hasFeedback && !this.allowBlank){
9649 cls: 'glyphicon form-control-feedback'
9653 cls : 'has-feedback',
9662 if (this.before || this.after) {
9665 cls : 'input-group',
9669 inputblock.cn.push({
9671 cls : 'input-group-addon',
9676 inputblock.cn.push(input);
9678 if(this.hasFeedback && !this.allowBlank){
9679 inputblock.cls += ' has-feedback';
9680 inputblock.cn.push(feedback);
9684 inputblock.cn.push({
9686 cls : 'input-group-addon',
9693 if (align ==='left' && this.fieldLabel.length) {
9698 cls : 'control-label',
9699 html : this.fieldLabel
9710 if(this.labelWidth > 12){
9711 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9714 if(this.labelWidth < 13 && this.labelmd == 0){
9715 this.labelmd = this.labelWidth;
9718 if(this.labellg > 0){
9719 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9720 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9723 if(this.labelmd > 0){
9724 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9725 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9728 if(this.labelsm > 0){
9729 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9730 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9733 if(this.labelxs > 0){
9734 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9735 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9738 } else if ( this.fieldLabel.length) {
9743 //cls : 'input-group-addon',
9744 html : this.fieldLabel
9762 if (this.disabled) {
9763 input.disabled=true;
9770 * return the real textarea element.
9772 inputEl: function ()
9774 return this.el.select('textarea.form-control',true).first();
9778 * Clear any invalid styles/messages for this field
9780 clearInvalid : function()
9783 if(!this.el || this.preventMark){ // not rendered
9787 var label = this.el.select('label', true).first();
9788 var icon = this.el.select('i.fa-star', true).first();
9794 this.el.removeClass(this.invalidClass);
9796 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9798 var feedback = this.el.select('.form-control-feedback', true).first();
9801 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9806 this.fireEvent('valid', this);
9810 * Mark this field as valid
9812 markValid : function()
9814 if(!this.el || this.preventMark){ // not rendered
9818 this.el.removeClass([this.invalidClass, this.validClass]);
9820 var feedback = this.el.select('.form-control-feedback', true).first();
9823 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9826 if(this.disabled || this.allowBlank){
9830 var label = this.el.select('label', true).first();
9831 var icon = this.el.select('i.fa-star', true).first();
9837 this.el.addClass(this.validClass);
9839 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9841 var feedback = this.el.select('.form-control-feedback', true).first();
9844 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9845 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9850 this.fireEvent('valid', this);
9854 * Mark this field as invalid
9855 * @param {String} msg The validation message
9857 markInvalid : function(msg)
9859 if(!this.el || this.preventMark){ // not rendered
9863 this.el.removeClass([this.invalidClass, this.validClass]);
9865 var feedback = this.el.select('.form-control-feedback', true).first();
9868 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9871 if(this.disabled || this.allowBlank){
9875 var label = this.el.select('label', true).first();
9876 var icon = this.el.select('i.fa-star', true).first();
9878 if(!this.getValue().length && label && !icon){
9879 this.el.createChild({
9881 cls : 'text-danger fa fa-lg fa-star',
9882 tooltip : 'This field is required',
9883 style : 'margin-right:5px;'
9887 this.el.addClass(this.invalidClass);
9889 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9891 var feedback = this.el.select('.form-control-feedback', true).first();
9894 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9896 if(this.getValue().length || this.forceFeedback){
9897 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9904 this.fireEvent('invalid', this, msg);
9912 * trigger field - base class for combo..
9917 * @class Roo.bootstrap.TriggerField
9918 * @extends Roo.bootstrap.Input
9919 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9920 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9921 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9922 * for which you can provide a custom implementation. For example:
9924 var trigger = new Roo.bootstrap.TriggerField();
9925 trigger.onTriggerClick = myTriggerFn;
9926 trigger.applyTo('my-field');
9929 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9930 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9931 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
9932 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9933 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9936 * Create a new TriggerField.
9937 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9938 * to the base TextField)
9940 Roo.bootstrap.TriggerField = function(config){
9941 this.mimicing = false;
9942 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9945 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
9947 * @cfg {String} triggerClass A CSS class to apply to the trigger
9950 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9955 * @cfg {Boolean} removable (true|false) special filter default false
9959 /** @cfg {Boolean} grow @hide */
9960 /** @cfg {Number} growMin @hide */
9961 /** @cfg {Number} growMax @hide */
9967 autoSize: Roo.emptyFn,
9974 actionMode : 'wrap',
9979 getAutoCreate : function(){
9981 var align = this.labelAlign || this.parentLabelAlign();
9986 cls: 'form-group' //input-group
9993 type : this.inputType,
9994 cls : 'form-control',
9995 autocomplete: 'new-password',
9996 placeholder : this.placeholder || ''
10000 input.name = this.name;
10003 input.cls += ' input-' + this.size;
10006 if (this.disabled) {
10007 input.disabled=true;
10010 var inputblock = input;
10012 if(this.hasFeedback && !this.allowBlank){
10016 cls: 'glyphicon form-control-feedback'
10019 if(this.removable && !this.editable && !this.tickable){
10021 cls : 'has-feedback',
10027 cls : 'roo-combo-removable-btn close'
10034 cls : 'has-feedback',
10043 if(this.removable && !this.editable && !this.tickable){
10045 cls : 'roo-removable',
10051 cls : 'roo-combo-removable-btn close'
10058 if (this.before || this.after) {
10061 cls : 'input-group',
10065 inputblock.cn.push({
10067 cls : 'input-group-addon',
10072 inputblock.cn.push(input);
10074 if(this.hasFeedback && !this.allowBlank){
10075 inputblock.cls += ' has-feedback';
10076 inputblock.cn.push(feedback);
10080 inputblock.cn.push({
10082 cls : 'input-group-addon',
10095 cls: 'form-hidden-field'
10109 cls: 'form-hidden-field'
10113 cls: 'roo-select2-choices',
10117 cls: 'roo-select2-search-field',
10130 cls: 'roo-select2-container input-group',
10135 // cls: 'typeahead typeahead-long dropdown-menu',
10136 // style: 'display:none'
10141 if(!this.multiple && this.showToggleBtn){
10147 if (this.caret != false) {
10150 cls: 'fa fa-' + this.caret
10157 cls : 'input-group-addon btn dropdown-toggle',
10162 cls: 'combobox-clear',
10176 combobox.cls += ' roo-select2-container-multi';
10179 if (align ==='left' && this.fieldLabel.length) {
10181 cfg.cls += ' roo-form-group-label-left';
10186 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10187 tooltip : 'This field is required'
10192 cls : 'control-label',
10193 html : this.fieldLabel
10205 var labelCfg = cfg.cn[1];
10206 var contentCfg = cfg.cn[2];
10208 if(this.indicatorpos == 'right'){
10213 cls : 'control-label',
10217 html : this.fieldLabel
10221 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10222 tooltip : 'This field is required'
10235 labelCfg = cfg.cn[0];
10236 contentCfg = cfg.cn[1];
10239 if(this.labelWidth > 12){
10240 labelCfg.style = "width: " + this.labelWidth + 'px';
10243 if(this.labelWidth < 13 && this.labelmd == 0){
10244 this.labelmd = this.labelWidth;
10247 if(this.labellg > 0){
10248 labelCfg.cls += ' col-lg-' + this.labellg;
10249 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10252 if(this.labelmd > 0){
10253 labelCfg.cls += ' col-md-' + this.labelmd;
10254 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10257 if(this.labelsm > 0){
10258 labelCfg.cls += ' col-sm-' + this.labelsm;
10259 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10262 if(this.labelxs > 0){
10263 labelCfg.cls += ' col-xs-' + this.labelxs;
10264 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10267 } else if ( this.fieldLabel.length) {
10268 // Roo.log(" label");
10272 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10273 tooltip : 'This field is required'
10277 //cls : 'input-group-addon',
10278 html : this.fieldLabel
10286 if(this.indicatorpos == 'right'){
10294 html : this.fieldLabel
10298 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10299 tooltip : 'This field is required'
10312 // Roo.log(" no label && no align");
10319 ['xs','sm','md','lg'].map(function(size){
10320 if (settings[size]) {
10321 cfg.cls += ' col-' + size + '-' + settings[size];
10332 onResize : function(w, h){
10333 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10334 // if(typeof w == 'number'){
10335 // var x = w - this.trigger.getWidth();
10336 // this.inputEl().setWidth(this.adjustWidth('input', x));
10337 // this.trigger.setStyle('left', x+'px');
10342 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10345 getResizeEl : function(){
10346 return this.inputEl();
10350 getPositionEl : function(){
10351 return this.inputEl();
10355 alignErrorIcon : function(){
10356 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10360 initEvents : function(){
10364 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10365 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10366 if(!this.multiple && this.showToggleBtn){
10367 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10368 if(this.hideTrigger){
10369 this.trigger.setDisplayed(false);
10371 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10375 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10378 if(this.removable && !this.editable && !this.tickable){
10379 var close = this.closeTriggerEl();
10382 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10383 close.on('click', this.removeBtnClick, this, close);
10387 //this.trigger.addClassOnOver('x-form-trigger-over');
10388 //this.trigger.addClassOnClick('x-form-trigger-click');
10391 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10395 closeTriggerEl : function()
10397 var close = this.el.select('.roo-combo-removable-btn', true).first();
10398 return close ? close : false;
10401 removeBtnClick : function(e, h, el)
10403 e.preventDefault();
10405 if(this.fireEvent("remove", this) !== false){
10407 this.fireEvent("afterremove", this)
10411 createList : function()
10413 this.list = Roo.get(document.body).createChild({
10415 cls: 'typeahead typeahead-long dropdown-menu',
10416 style: 'display:none'
10419 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10424 initTrigger : function(){
10429 onDestroy : function(){
10431 this.trigger.removeAllListeners();
10432 // this.trigger.remove();
10435 // this.wrap.remove();
10437 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10441 onFocus : function(){
10442 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10444 if(!this.mimicing){
10445 this.wrap.addClass('x-trigger-wrap-focus');
10446 this.mimicing = true;
10447 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10448 if(this.monitorTab){
10449 this.el.on("keydown", this.checkTab, this);
10456 checkTab : function(e){
10457 if(e.getKey() == e.TAB){
10458 this.triggerBlur();
10463 onBlur : function(){
10468 mimicBlur : function(e, t){
10470 if(!this.wrap.contains(t) && this.validateBlur()){
10471 this.triggerBlur();
10477 triggerBlur : function(){
10478 this.mimicing = false;
10479 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10480 if(this.monitorTab){
10481 this.el.un("keydown", this.checkTab, this);
10483 //this.wrap.removeClass('x-trigger-wrap-focus');
10484 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10488 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10489 validateBlur : function(e, t){
10494 onDisable : function(){
10495 this.inputEl().dom.disabled = true;
10496 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10498 // this.wrap.addClass('x-item-disabled');
10503 onEnable : function(){
10504 this.inputEl().dom.disabled = false;
10505 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10507 // this.el.removeClass('x-item-disabled');
10512 onShow : function(){
10513 var ae = this.getActionEl();
10516 ae.dom.style.display = '';
10517 ae.dom.style.visibility = 'visible';
10523 onHide : function(){
10524 var ae = this.getActionEl();
10525 ae.dom.style.display = 'none';
10529 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10530 * by an implementing function.
10532 * @param {EventObject} e
10534 onTriggerClick : Roo.emptyFn
10538 * Ext JS Library 1.1.1
10539 * Copyright(c) 2006-2007, Ext JS, LLC.
10541 * Originally Released Under LGPL - original licence link has changed is not relivant.
10544 * <script type="text/javascript">
10549 * @class Roo.data.SortTypes
10551 * Defines the default sorting (casting?) comparison functions used when sorting data.
10553 Roo.data.SortTypes = {
10555 * Default sort that does nothing
10556 * @param {Mixed} s The value being converted
10557 * @return {Mixed} The comparison value
10559 none : function(s){
10564 * The regular expression used to strip tags
10568 stripTagsRE : /<\/?[^>]+>/gi,
10571 * Strips all HTML tags to sort on text only
10572 * @param {Mixed} s The value being converted
10573 * @return {String} The comparison value
10575 asText : function(s){
10576 return String(s).replace(this.stripTagsRE, "");
10580 * Strips all HTML tags to sort on text only - Case insensitive
10581 * @param {Mixed} s The value being converted
10582 * @return {String} The comparison value
10584 asUCText : function(s){
10585 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10589 * Case insensitive string
10590 * @param {Mixed} s The value being converted
10591 * @return {String} The comparison value
10593 asUCString : function(s) {
10594 return String(s).toUpperCase();
10599 * @param {Mixed} s The value being converted
10600 * @return {Number} The comparison value
10602 asDate : function(s) {
10606 if(s instanceof Date){
10607 return s.getTime();
10609 return Date.parse(String(s));
10614 * @param {Mixed} s The value being converted
10615 * @return {Float} The comparison value
10617 asFloat : function(s) {
10618 var val = parseFloat(String(s).replace(/,/g, ""));
10627 * @param {Mixed} s The value being converted
10628 * @return {Number} The comparison value
10630 asInt : function(s) {
10631 var val = parseInt(String(s).replace(/,/g, ""));
10639 * Ext JS Library 1.1.1
10640 * Copyright(c) 2006-2007, Ext JS, LLC.
10642 * Originally Released Under LGPL - original licence link has changed is not relivant.
10645 * <script type="text/javascript">
10649 * @class Roo.data.Record
10650 * Instances of this class encapsulate both record <em>definition</em> information, and record
10651 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10652 * to access Records cached in an {@link Roo.data.Store} object.<br>
10654 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10655 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10658 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10660 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10661 * {@link #create}. The parameters are the same.
10662 * @param {Array} data An associative Array of data values keyed by the field name.
10663 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10664 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10665 * not specified an integer id is generated.
10667 Roo.data.Record = function(data, id){
10668 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10673 * Generate a constructor for a specific record layout.
10674 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10675 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10676 * Each field definition object may contain the following properties: <ul>
10677 * <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,
10678 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10679 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10680 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10681 * is being used, then this is a string containing the javascript expression to reference the data relative to
10682 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10683 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10684 * this may be omitted.</p></li>
10685 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10686 * <ul><li>auto (Default, implies no conversion)</li>
10691 * <li>date</li></ul></p></li>
10692 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10693 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10694 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10695 * by the Reader into an object that will be stored in the Record. It is passed the
10696 * following parameters:<ul>
10697 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10699 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10701 * <br>usage:<br><pre><code>
10702 var TopicRecord = Roo.data.Record.create(
10703 {name: 'title', mapping: 'topic_title'},
10704 {name: 'author', mapping: 'username'},
10705 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10706 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10707 {name: 'lastPoster', mapping: 'user2'},
10708 {name: 'excerpt', mapping: 'post_text'}
10711 var myNewRecord = new TopicRecord({
10712 title: 'Do my job please',
10715 lastPost: new Date(),
10716 lastPoster: 'Animal',
10717 excerpt: 'No way dude!'
10719 myStore.add(myNewRecord);
10724 Roo.data.Record.create = function(o){
10725 var f = function(){
10726 f.superclass.constructor.apply(this, arguments);
10728 Roo.extend(f, Roo.data.Record);
10729 var p = f.prototype;
10730 p.fields = new Roo.util.MixedCollection(false, function(field){
10733 for(var i = 0, len = o.length; i < len; i++){
10734 p.fields.add(new Roo.data.Field(o[i]));
10736 f.getField = function(name){
10737 return p.fields.get(name);
10742 Roo.data.Record.AUTO_ID = 1000;
10743 Roo.data.Record.EDIT = 'edit';
10744 Roo.data.Record.REJECT = 'reject';
10745 Roo.data.Record.COMMIT = 'commit';
10747 Roo.data.Record.prototype = {
10749 * Readonly flag - true if this record has been modified.
10758 join : function(store){
10759 this.store = store;
10763 * Set the named field to the specified value.
10764 * @param {String} name The name of the field to set.
10765 * @param {Object} value The value to set the field to.
10767 set : function(name, value){
10768 if(this.data[name] == value){
10772 if(!this.modified){
10773 this.modified = {};
10775 if(typeof this.modified[name] == 'undefined'){
10776 this.modified[name] = this.data[name];
10778 this.data[name] = value;
10779 if(!this.editing && this.store){
10780 this.store.afterEdit(this);
10785 * Get the value of the named field.
10786 * @param {String} name The name of the field to get the value of.
10787 * @return {Object} The value of the field.
10789 get : function(name){
10790 return this.data[name];
10794 beginEdit : function(){
10795 this.editing = true;
10796 this.modified = {};
10800 cancelEdit : function(){
10801 this.editing = false;
10802 delete this.modified;
10806 endEdit : function(){
10807 this.editing = false;
10808 if(this.dirty && this.store){
10809 this.store.afterEdit(this);
10814 * Usually called by the {@link Roo.data.Store} which owns the Record.
10815 * Rejects all changes made to the Record since either creation, or the last commit operation.
10816 * Modified fields are reverted to their original values.
10818 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10819 * of reject operations.
10821 reject : function(){
10822 var m = this.modified;
10824 if(typeof m[n] != "function"){
10825 this.data[n] = m[n];
10828 this.dirty = false;
10829 delete this.modified;
10830 this.editing = false;
10832 this.store.afterReject(this);
10837 * Usually called by the {@link Roo.data.Store} which owns the Record.
10838 * Commits all changes made to the Record since either creation, or the last commit operation.
10840 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10841 * of commit operations.
10843 commit : function(){
10844 this.dirty = false;
10845 delete this.modified;
10846 this.editing = false;
10848 this.store.afterCommit(this);
10853 hasError : function(){
10854 return this.error != null;
10858 clearError : function(){
10863 * Creates a copy of this record.
10864 * @param {String} id (optional) A new record id if you don't want to use this record's id
10867 copy : function(newId) {
10868 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10872 * Ext JS Library 1.1.1
10873 * Copyright(c) 2006-2007, Ext JS, LLC.
10875 * Originally Released Under LGPL - original licence link has changed is not relivant.
10878 * <script type="text/javascript">
10884 * @class Roo.data.Store
10885 * @extends Roo.util.Observable
10886 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10887 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10889 * 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
10890 * has no knowledge of the format of the data returned by the Proxy.<br>
10892 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10893 * instances from the data object. These records are cached and made available through accessor functions.
10895 * Creates a new Store.
10896 * @param {Object} config A config object containing the objects needed for the Store to access data,
10897 * and read the data into Records.
10899 Roo.data.Store = function(config){
10900 this.data = new Roo.util.MixedCollection(false);
10901 this.data.getKey = function(o){
10904 this.baseParams = {};
10906 this.paramNames = {
10911 "multisort" : "_multisort"
10914 if(config && config.data){
10915 this.inlineData = config.data;
10916 delete config.data;
10919 Roo.apply(this, config);
10921 if(this.reader){ // reader passed
10922 this.reader = Roo.factory(this.reader, Roo.data);
10923 this.reader.xmodule = this.xmodule || false;
10924 if(!this.recordType){
10925 this.recordType = this.reader.recordType;
10927 if(this.reader.onMetaChange){
10928 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10932 if(this.recordType){
10933 this.fields = this.recordType.prototype.fields;
10935 this.modified = [];
10939 * @event datachanged
10940 * Fires when the data cache has changed, and a widget which is using this Store
10941 * as a Record cache should refresh its view.
10942 * @param {Store} this
10944 datachanged : true,
10946 * @event metachange
10947 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10948 * @param {Store} this
10949 * @param {Object} meta The JSON metadata
10954 * Fires when Records have been added to the Store
10955 * @param {Store} this
10956 * @param {Roo.data.Record[]} records The array of Records added
10957 * @param {Number} index The index at which the record(s) were added
10962 * Fires when a Record has been removed from the Store
10963 * @param {Store} this
10964 * @param {Roo.data.Record} record The Record that was removed
10965 * @param {Number} index The index at which the record was removed
10970 * Fires when a Record has been updated
10971 * @param {Store} this
10972 * @param {Roo.data.Record} record The Record that was updated
10973 * @param {String} operation The update operation being performed. Value may be one of:
10975 Roo.data.Record.EDIT
10976 Roo.data.Record.REJECT
10977 Roo.data.Record.COMMIT
10983 * Fires when the data cache has been cleared.
10984 * @param {Store} this
10988 * @event beforeload
10989 * Fires before a request is made for a new data object. If the beforeload handler returns false
10990 * the load action will be canceled.
10991 * @param {Store} this
10992 * @param {Object} options The loading options that were specified (see {@link #load} for details)
10996 * @event beforeloadadd
10997 * Fires after a new set of Records has been loaded.
10998 * @param {Store} this
10999 * @param {Roo.data.Record[]} records The Records that were loaded
11000 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11002 beforeloadadd : true,
11005 * Fires after a new set of Records has been loaded, before they are added to the store.
11006 * @param {Store} this
11007 * @param {Roo.data.Record[]} records The Records that were loaded
11008 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11009 * @params {Object} return from reader
11013 * @event loadexception
11014 * Fires if an exception occurs in the Proxy during loading.
11015 * Called with the signature of the Proxy's "loadexception" event.
11016 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11019 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11020 * @param {Object} load options
11021 * @param {Object} jsonData from your request (normally this contains the Exception)
11023 loadexception : true
11027 this.proxy = Roo.factory(this.proxy, Roo.data);
11028 this.proxy.xmodule = this.xmodule || false;
11029 this.relayEvents(this.proxy, ["loadexception"]);
11031 this.sortToggle = {};
11032 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11034 Roo.data.Store.superclass.constructor.call(this);
11036 if(this.inlineData){
11037 this.loadData(this.inlineData);
11038 delete this.inlineData;
11042 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11044 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11045 * without a remote query - used by combo/forms at present.
11049 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11052 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11055 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11056 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11059 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11060 * on any HTTP request
11063 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11066 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11070 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11071 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11073 remoteSort : false,
11076 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11077 * loaded or when a record is removed. (defaults to false).
11079 pruneModifiedRecords : false,
11082 lastOptions : null,
11085 * Add Records to the Store and fires the add event.
11086 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11088 add : function(records){
11089 records = [].concat(records);
11090 for(var i = 0, len = records.length; i < len; i++){
11091 records[i].join(this);
11093 var index = this.data.length;
11094 this.data.addAll(records);
11095 this.fireEvent("add", this, records, index);
11099 * Remove a Record from the Store and fires the remove event.
11100 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11102 remove : function(record){
11103 var index = this.data.indexOf(record);
11104 this.data.removeAt(index);
11105 if(this.pruneModifiedRecords){
11106 this.modified.remove(record);
11108 this.fireEvent("remove", this, record, index);
11112 * Remove all Records from the Store and fires the clear event.
11114 removeAll : function(){
11116 if(this.pruneModifiedRecords){
11117 this.modified = [];
11119 this.fireEvent("clear", this);
11123 * Inserts Records to the Store at the given index and fires the add event.
11124 * @param {Number} index The start index at which to insert the passed Records.
11125 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11127 insert : function(index, records){
11128 records = [].concat(records);
11129 for(var i = 0, len = records.length; i < len; i++){
11130 this.data.insert(index, records[i]);
11131 records[i].join(this);
11133 this.fireEvent("add", this, records, index);
11137 * Get the index within the cache of the passed Record.
11138 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11139 * @return {Number} The index of the passed Record. Returns -1 if not found.
11141 indexOf : function(record){
11142 return this.data.indexOf(record);
11146 * Get the index within the cache of the Record with the passed id.
11147 * @param {String} id The id of the Record to find.
11148 * @return {Number} The index of the Record. Returns -1 if not found.
11150 indexOfId : function(id){
11151 return this.data.indexOfKey(id);
11155 * Get the Record with the specified id.
11156 * @param {String} id The id of the Record to find.
11157 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11159 getById : function(id){
11160 return this.data.key(id);
11164 * Get the Record at the specified index.
11165 * @param {Number} index The index of the Record to find.
11166 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11168 getAt : function(index){
11169 return this.data.itemAt(index);
11173 * Returns a range of Records between specified indices.
11174 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11175 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11176 * @return {Roo.data.Record[]} An array of Records
11178 getRange : function(start, end){
11179 return this.data.getRange(start, end);
11183 storeOptions : function(o){
11184 o = Roo.apply({}, o);
11187 this.lastOptions = o;
11191 * Loads the Record cache from the configured Proxy using the configured Reader.
11193 * If using remote paging, then the first load call must specify the <em>start</em>
11194 * and <em>limit</em> properties in the options.params property to establish the initial
11195 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11197 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11198 * and this call will return before the new data has been loaded. Perform any post-processing
11199 * in a callback function, or in a "load" event handler.</strong>
11201 * @param {Object} options An object containing properties which control loading options:<ul>
11202 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11203 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11204 * passed the following arguments:<ul>
11205 * <li>r : Roo.data.Record[]</li>
11206 * <li>options: Options object from the load call</li>
11207 * <li>success: Boolean success indicator</li></ul></li>
11208 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11209 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11212 load : function(options){
11213 options = options || {};
11214 if(this.fireEvent("beforeload", this, options) !== false){
11215 this.storeOptions(options);
11216 var p = Roo.apply(options.params || {}, this.baseParams);
11217 // if meta was not loaded from remote source.. try requesting it.
11218 if (!this.reader.metaFromRemote) {
11219 p._requestMeta = 1;
11221 if(this.sortInfo && this.remoteSort){
11222 var pn = this.paramNames;
11223 p[pn["sort"]] = this.sortInfo.field;
11224 p[pn["dir"]] = this.sortInfo.direction;
11226 if (this.multiSort) {
11227 var pn = this.paramNames;
11228 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11231 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11236 * Reloads the Record cache from the configured Proxy using the configured Reader and
11237 * the options from the last load operation performed.
11238 * @param {Object} options (optional) An object containing properties which may override the options
11239 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11240 * the most recently used options are reused).
11242 reload : function(options){
11243 this.load(Roo.applyIf(options||{}, this.lastOptions));
11247 // Called as a callback by the Reader during a load operation.
11248 loadRecords : function(o, options, success){
11249 if(!o || success === false){
11250 if(success !== false){
11251 this.fireEvent("load", this, [], options, o);
11253 if(options.callback){
11254 options.callback.call(options.scope || this, [], options, false);
11258 // if data returned failure - throw an exception.
11259 if (o.success === false) {
11260 // show a message if no listener is registered.
11261 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11262 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11264 // loadmask wil be hooked into this..
11265 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11268 var r = o.records, t = o.totalRecords || r.length;
11270 this.fireEvent("beforeloadadd", this, r, options, o);
11272 if(!options || options.add !== true){
11273 if(this.pruneModifiedRecords){
11274 this.modified = [];
11276 for(var i = 0, len = r.length; i < len; i++){
11280 this.data = this.snapshot;
11281 delete this.snapshot;
11284 this.data.addAll(r);
11285 this.totalLength = t;
11287 this.fireEvent("datachanged", this);
11289 this.totalLength = Math.max(t, this.data.length+r.length);
11293 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11295 var e = new Roo.data.Record({});
11297 e.set(this.parent.displayField, this.parent.emptyTitle);
11298 e.set(this.parent.valueField, '');
11303 this.fireEvent("load", this, r, options, o);
11304 if(options.callback){
11305 options.callback.call(options.scope || this, r, options, true);
11311 * Loads data from a passed data block. A Reader which understands the format of the data
11312 * must have been configured in the constructor.
11313 * @param {Object} data The data block from which to read the Records. The format of the data expected
11314 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11315 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11317 loadData : function(o, append){
11318 var r = this.reader.readRecords(o);
11319 this.loadRecords(r, {add: append}, true);
11323 * Gets the number of cached records.
11325 * <em>If using paging, this may not be the total size of the dataset. If the data object
11326 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11327 * the data set size</em>
11329 getCount : function(){
11330 return this.data.length || 0;
11334 * Gets the total number of records in the dataset as returned by the server.
11336 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11337 * the dataset size</em>
11339 getTotalCount : function(){
11340 return this.totalLength || 0;
11344 * Returns the sort state of the Store as an object with two properties:
11346 field {String} The name of the field by which the Records are sorted
11347 direction {String} The sort order, "ASC" or "DESC"
11350 getSortState : function(){
11351 return this.sortInfo;
11355 applySort : function(){
11356 if(this.sortInfo && !this.remoteSort){
11357 var s = this.sortInfo, f = s.field;
11358 var st = this.fields.get(f).sortType;
11359 var fn = function(r1, r2){
11360 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11361 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11363 this.data.sort(s.direction, fn);
11364 if(this.snapshot && this.snapshot != this.data){
11365 this.snapshot.sort(s.direction, fn);
11371 * Sets the default sort column and order to be used by the next load operation.
11372 * @param {String} fieldName The name of the field to sort by.
11373 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11375 setDefaultSort : function(field, dir){
11376 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11380 * Sort the Records.
11381 * If remote sorting is used, the sort is performed on the server, and the cache is
11382 * reloaded. If local sorting is used, the cache is sorted internally.
11383 * @param {String} fieldName The name of the field to sort by.
11384 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11386 sort : function(fieldName, dir){
11387 var f = this.fields.get(fieldName);
11389 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11391 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11392 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11397 this.sortToggle[f.name] = dir;
11398 this.sortInfo = {field: f.name, direction: dir};
11399 if(!this.remoteSort){
11401 this.fireEvent("datachanged", this);
11403 this.load(this.lastOptions);
11408 * Calls the specified function for each of the Records in the cache.
11409 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11410 * Returning <em>false</em> aborts and exits the iteration.
11411 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11413 each : function(fn, scope){
11414 this.data.each(fn, scope);
11418 * Gets all records modified since the last commit. Modified records are persisted across load operations
11419 * (e.g., during paging).
11420 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11422 getModifiedRecords : function(){
11423 return this.modified;
11427 createFilterFn : function(property, value, anyMatch){
11428 if(!value.exec){ // not a regex
11429 value = String(value);
11430 if(value.length == 0){
11433 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11435 return function(r){
11436 return value.test(r.data[property]);
11441 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11442 * @param {String} property A field on your records
11443 * @param {Number} start The record index to start at (defaults to 0)
11444 * @param {Number} end The last record index to include (defaults to length - 1)
11445 * @return {Number} The sum
11447 sum : function(property, start, end){
11448 var rs = this.data.items, v = 0;
11449 start = start || 0;
11450 end = (end || end === 0) ? end : rs.length-1;
11452 for(var i = start; i <= end; i++){
11453 v += (rs[i].data[property] || 0);
11459 * Filter the records by a specified property.
11460 * @param {String} field A field on your records
11461 * @param {String/RegExp} value Either a string that the field
11462 * should start with or a RegExp to test against the field
11463 * @param {Boolean} anyMatch True to match any part not just the beginning
11465 filter : function(property, value, anyMatch){
11466 var fn = this.createFilterFn(property, value, anyMatch);
11467 return fn ? this.filterBy(fn) : this.clearFilter();
11471 * Filter by a function. The specified function will be called with each
11472 * record in this data source. If the function returns true the record is included,
11473 * otherwise it is filtered.
11474 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11475 * @param {Object} scope (optional) The scope of the function (defaults to this)
11477 filterBy : function(fn, scope){
11478 this.snapshot = this.snapshot || this.data;
11479 this.data = this.queryBy(fn, scope||this);
11480 this.fireEvent("datachanged", this);
11484 * Query the records by a specified property.
11485 * @param {String} field A field on your records
11486 * @param {String/RegExp} value Either a string that the field
11487 * should start with or a RegExp to test against the field
11488 * @param {Boolean} anyMatch True to match any part not just the beginning
11489 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11491 query : function(property, value, anyMatch){
11492 var fn = this.createFilterFn(property, value, anyMatch);
11493 return fn ? this.queryBy(fn) : this.data.clone();
11497 * Query by a function. The specified function will be called with each
11498 * record in this data source. If the function returns true the record is included
11500 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11501 * @param {Object} scope (optional) The scope of the function (defaults to this)
11502 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11504 queryBy : function(fn, scope){
11505 var data = this.snapshot || this.data;
11506 return data.filterBy(fn, scope||this);
11510 * Collects unique values for a particular dataIndex from this store.
11511 * @param {String} dataIndex The property to collect
11512 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11513 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11514 * @return {Array} An array of the unique values
11516 collect : function(dataIndex, allowNull, bypassFilter){
11517 var d = (bypassFilter === true && this.snapshot) ?
11518 this.snapshot.items : this.data.items;
11519 var v, sv, r = [], l = {};
11520 for(var i = 0, len = d.length; i < len; i++){
11521 v = d[i].data[dataIndex];
11523 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11532 * Revert to a view of the Record cache with no filtering applied.
11533 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11535 clearFilter : function(suppressEvent){
11536 if(this.snapshot && this.snapshot != this.data){
11537 this.data = this.snapshot;
11538 delete this.snapshot;
11539 if(suppressEvent !== true){
11540 this.fireEvent("datachanged", this);
11546 afterEdit : function(record){
11547 if(this.modified.indexOf(record) == -1){
11548 this.modified.push(record);
11550 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11554 afterReject : function(record){
11555 this.modified.remove(record);
11556 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11560 afterCommit : function(record){
11561 this.modified.remove(record);
11562 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11566 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11567 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11569 commitChanges : function(){
11570 var m = this.modified.slice(0);
11571 this.modified = [];
11572 for(var i = 0, len = m.length; i < len; i++){
11578 * Cancel outstanding changes on all changed records.
11580 rejectChanges : function(){
11581 var m = this.modified.slice(0);
11582 this.modified = [];
11583 for(var i = 0, len = m.length; i < len; i++){
11588 onMetaChange : function(meta, rtype, o){
11589 this.recordType = rtype;
11590 this.fields = rtype.prototype.fields;
11591 delete this.snapshot;
11592 this.sortInfo = meta.sortInfo || this.sortInfo;
11593 this.modified = [];
11594 this.fireEvent('metachange', this, this.reader.meta);
11597 moveIndex : function(data, type)
11599 var index = this.indexOf(data);
11601 var newIndex = index + type;
11605 this.insert(newIndex, data);
11610 * Ext JS Library 1.1.1
11611 * Copyright(c) 2006-2007, Ext JS, LLC.
11613 * Originally Released Under LGPL - original licence link has changed is not relivant.
11616 * <script type="text/javascript">
11620 * @class Roo.data.SimpleStore
11621 * @extends Roo.data.Store
11622 * Small helper class to make creating Stores from Array data easier.
11623 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11624 * @cfg {Array} fields An array of field definition objects, or field name strings.
11625 * @cfg {Array} data The multi-dimensional array of data
11627 * @param {Object} config
11629 Roo.data.SimpleStore = function(config){
11630 Roo.data.SimpleStore.superclass.constructor.call(this, {
11632 reader: new Roo.data.ArrayReader({
11635 Roo.data.Record.create(config.fields)
11637 proxy : new Roo.data.MemoryProxy(config.data)
11641 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11643 * Ext JS Library 1.1.1
11644 * Copyright(c) 2006-2007, Ext JS, LLC.
11646 * Originally Released Under LGPL - original licence link has changed is not relivant.
11649 * <script type="text/javascript">
11654 * @extends Roo.data.Store
11655 * @class Roo.data.JsonStore
11656 * Small helper class to make creating Stores for JSON data easier. <br/>
11658 var store = new Roo.data.JsonStore({
11659 url: 'get-images.php',
11661 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11664 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11665 * JsonReader and HttpProxy (unless inline data is provided).</b>
11666 * @cfg {Array} fields An array of field definition objects, or field name strings.
11668 * @param {Object} config
11670 Roo.data.JsonStore = function(c){
11671 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11672 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11673 reader: new Roo.data.JsonReader(c, c.fields)
11676 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11678 * Ext JS Library 1.1.1
11679 * Copyright(c) 2006-2007, Ext JS, LLC.
11681 * Originally Released Under LGPL - original licence link has changed is not relivant.
11684 * <script type="text/javascript">
11688 Roo.data.Field = function(config){
11689 if(typeof config == "string"){
11690 config = {name: config};
11692 Roo.apply(this, config);
11695 this.type = "auto";
11698 var st = Roo.data.SortTypes;
11699 // named sortTypes are supported, here we look them up
11700 if(typeof this.sortType == "string"){
11701 this.sortType = st[this.sortType];
11704 // set default sortType for strings and dates
11705 if(!this.sortType){
11708 this.sortType = st.asUCString;
11711 this.sortType = st.asDate;
11714 this.sortType = st.none;
11719 var stripRe = /[\$,%]/g;
11721 // prebuilt conversion function for this field, instead of
11722 // switching every time we're reading a value
11724 var cv, dateFormat = this.dateFormat;
11729 cv = function(v){ return v; };
11732 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11736 return v !== undefined && v !== null && v !== '' ?
11737 parseInt(String(v).replace(stripRe, ""), 10) : '';
11742 return v !== undefined && v !== null && v !== '' ?
11743 parseFloat(String(v).replace(stripRe, ""), 10) : '';
11748 cv = function(v){ return v === true || v === "true" || v == 1; };
11755 if(v instanceof Date){
11759 if(dateFormat == "timestamp"){
11760 return new Date(v*1000);
11762 return Date.parseDate(v, dateFormat);
11764 var parsed = Date.parse(v);
11765 return parsed ? new Date(parsed) : null;
11774 Roo.data.Field.prototype = {
11782 * Ext JS Library 1.1.1
11783 * Copyright(c) 2006-2007, Ext JS, LLC.
11785 * Originally Released Under LGPL - original licence link has changed is not relivant.
11788 * <script type="text/javascript">
11791 // Base class for reading structured data from a data source. This class is intended to be
11792 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11795 * @class Roo.data.DataReader
11796 * Base class for reading structured data from a data source. This class is intended to be
11797 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11800 Roo.data.DataReader = function(meta, recordType){
11804 this.recordType = recordType instanceof Array ?
11805 Roo.data.Record.create(recordType) : recordType;
11808 Roo.data.DataReader.prototype = {
11810 * Create an empty record
11811 * @param {Object} data (optional) - overlay some values
11812 * @return {Roo.data.Record} record created.
11814 newRow : function(d) {
11816 this.recordType.prototype.fields.each(function(c) {
11818 case 'int' : da[c.name] = 0; break;
11819 case 'date' : da[c.name] = new Date(); break;
11820 case 'float' : da[c.name] = 0.0; break;
11821 case 'boolean' : da[c.name] = false; break;
11822 default : da[c.name] = ""; break;
11826 return new this.recordType(Roo.apply(da, d));
11831 * Ext JS Library 1.1.1
11832 * Copyright(c) 2006-2007, Ext JS, LLC.
11834 * Originally Released Under LGPL - original licence link has changed is not relivant.
11837 * <script type="text/javascript">
11841 * @class Roo.data.DataProxy
11842 * @extends Roo.data.Observable
11843 * This class is an abstract base class for implementations which provide retrieval of
11844 * unformatted data objects.<br>
11846 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11847 * (of the appropriate type which knows how to parse the data object) to provide a block of
11848 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11850 * Custom implementations must implement the load method as described in
11851 * {@link Roo.data.HttpProxy#load}.
11853 Roo.data.DataProxy = function(){
11856 * @event beforeload
11857 * Fires before a network request is made to retrieve a data object.
11858 * @param {Object} This DataProxy object.
11859 * @param {Object} params The params parameter to the load function.
11864 * Fires before the load method's callback is called.
11865 * @param {Object} This DataProxy object.
11866 * @param {Object} o The data object.
11867 * @param {Object} arg The callback argument object passed to the load function.
11871 * @event loadexception
11872 * Fires if an Exception occurs during data retrieval.
11873 * @param {Object} This DataProxy object.
11874 * @param {Object} o The data object.
11875 * @param {Object} arg The callback argument object passed to the load function.
11876 * @param {Object} e The Exception.
11878 loadexception : true
11880 Roo.data.DataProxy.superclass.constructor.call(this);
11883 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11886 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11890 * Ext JS Library 1.1.1
11891 * Copyright(c) 2006-2007, Ext JS, LLC.
11893 * Originally Released Under LGPL - original licence link has changed is not relivant.
11896 * <script type="text/javascript">
11899 * @class Roo.data.MemoryProxy
11900 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11901 * to the Reader when its load method is called.
11903 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11905 Roo.data.MemoryProxy = function(data){
11909 Roo.data.MemoryProxy.superclass.constructor.call(this);
11913 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11916 * Load data from the requested source (in this case an in-memory
11917 * data object passed to the constructor), read the data object into
11918 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11919 * process that block using the passed callback.
11920 * @param {Object} params This parameter is not used by the MemoryProxy class.
11921 * @param {Roo.data.DataReader} reader The Reader object which converts the data
11922 * object into a block of Roo.data.Records.
11923 * @param {Function} callback The function into which to pass the block of Roo.data.records.
11924 * The function must be passed <ul>
11925 * <li>The Record block object</li>
11926 * <li>The "arg" argument from the load function</li>
11927 * <li>A boolean success indicator</li>
11929 * @param {Object} scope The scope in which to call the callback
11930 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11932 load : function(params, reader, callback, scope, arg){
11933 params = params || {};
11936 result = reader.readRecords(this.data);
11938 this.fireEvent("loadexception", this, arg, null, e);
11939 callback.call(scope, null, arg, false);
11942 callback.call(scope, result, arg, true);
11946 update : function(params, records){
11951 * Ext JS Library 1.1.1
11952 * Copyright(c) 2006-2007, Ext JS, LLC.
11954 * Originally Released Under LGPL - original licence link has changed is not relivant.
11957 * <script type="text/javascript">
11960 * @class Roo.data.HttpProxy
11961 * @extends Roo.data.DataProxy
11962 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11963 * configured to reference a certain URL.<br><br>
11965 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11966 * from which the running page was served.<br><br>
11968 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11970 * Be aware that to enable the browser to parse an XML document, the server must set
11971 * the Content-Type header in the HTTP response to "text/xml".
11973 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
11974 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
11975 * will be used to make the request.
11977 Roo.data.HttpProxy = function(conn){
11978 Roo.data.HttpProxy.superclass.constructor.call(this);
11979 // is conn a conn config or a real conn?
11981 this.useAjax = !conn || !conn.events;
11985 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
11986 // thse are take from connection...
11989 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11992 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11993 * extra parameters to each request made by this object. (defaults to undefined)
11996 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11997 * to each request made by this object. (defaults to undefined)
12000 * @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)
12003 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12006 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12012 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12016 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12017 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12018 * a finer-grained basis than the DataProxy events.
12020 getConnection : function(){
12021 return this.useAjax ? Roo.Ajax : this.conn;
12025 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12026 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12027 * process that block using the passed callback.
12028 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12029 * for the request to the remote server.
12030 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12031 * object into a block of Roo.data.Records.
12032 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12033 * The function must be passed <ul>
12034 * <li>The Record block object</li>
12035 * <li>The "arg" argument from the load function</li>
12036 * <li>A boolean success indicator</li>
12038 * @param {Object} scope The scope in which to call the callback
12039 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12041 load : function(params, reader, callback, scope, arg){
12042 if(this.fireEvent("beforeload", this, params) !== false){
12044 params : params || {},
12046 callback : callback,
12051 callback : this.loadResponse,
12055 Roo.applyIf(o, this.conn);
12056 if(this.activeRequest){
12057 Roo.Ajax.abort(this.activeRequest);
12059 this.activeRequest = Roo.Ajax.request(o);
12061 this.conn.request(o);
12064 callback.call(scope||this, null, arg, false);
12069 loadResponse : function(o, success, response){
12070 delete this.activeRequest;
12072 this.fireEvent("loadexception", this, o, response);
12073 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12078 result = o.reader.read(response);
12080 this.fireEvent("loadexception", this, o, response, e);
12081 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12085 this.fireEvent("load", this, o, o.request.arg);
12086 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12090 update : function(dataSet){
12095 updateResponse : function(dataSet){
12100 * Ext JS Library 1.1.1
12101 * Copyright(c) 2006-2007, Ext JS, LLC.
12103 * Originally Released Under LGPL - original licence link has changed is not relivant.
12106 * <script type="text/javascript">
12110 * @class Roo.data.ScriptTagProxy
12111 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12112 * other than the originating domain of the running page.<br><br>
12114 * <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
12115 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12117 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12118 * source code that is used as the source inside a <script> tag.<br><br>
12120 * In order for the browser to process the returned data, the server must wrap the data object
12121 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12122 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12123 * depending on whether the callback name was passed:
12126 boolean scriptTag = false;
12127 String cb = request.getParameter("callback");
12130 response.setContentType("text/javascript");
12132 response.setContentType("application/x-json");
12134 Writer out = response.getWriter();
12136 out.write(cb + "(");
12138 out.print(dataBlock.toJsonString());
12145 * @param {Object} config A configuration object.
12147 Roo.data.ScriptTagProxy = function(config){
12148 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12149 Roo.apply(this, config);
12150 this.head = document.getElementsByTagName("head")[0];
12153 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12155 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12157 * @cfg {String} url The URL from which to request the data object.
12160 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12164 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12165 * the server the name of the callback function set up by the load call to process the returned data object.
12166 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12167 * javascript output which calls this named function passing the data object as its only parameter.
12169 callbackParam : "callback",
12171 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12172 * name to the request.
12177 * Load data from the configured URL, read the data object into
12178 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12179 * process that block using the passed callback.
12180 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12181 * for the request to the remote server.
12182 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12183 * object into a block of Roo.data.Records.
12184 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12185 * The function must be passed <ul>
12186 * <li>The Record block object</li>
12187 * <li>The "arg" argument from the load function</li>
12188 * <li>A boolean success indicator</li>
12190 * @param {Object} scope The scope in which to call the callback
12191 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12193 load : function(params, reader, callback, scope, arg){
12194 if(this.fireEvent("beforeload", this, params) !== false){
12196 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12198 var url = this.url;
12199 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12201 url += "&_dc=" + (new Date().getTime());
12203 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12206 cb : "stcCallback"+transId,
12207 scriptId : "stcScript"+transId,
12211 callback : callback,
12217 window[trans.cb] = function(o){
12218 conn.handleResponse(o, trans);
12221 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12223 if(this.autoAbort !== false){
12227 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12229 var script = document.createElement("script");
12230 script.setAttribute("src", url);
12231 script.setAttribute("type", "text/javascript");
12232 script.setAttribute("id", trans.scriptId);
12233 this.head.appendChild(script);
12235 this.trans = trans;
12237 callback.call(scope||this, null, arg, false);
12242 isLoading : function(){
12243 return this.trans ? true : false;
12247 * Abort the current server request.
12249 abort : function(){
12250 if(this.isLoading()){
12251 this.destroyTrans(this.trans);
12256 destroyTrans : function(trans, isLoaded){
12257 this.head.removeChild(document.getElementById(trans.scriptId));
12258 clearTimeout(trans.timeoutId);
12260 window[trans.cb] = undefined;
12262 delete window[trans.cb];
12265 // if hasn't been loaded, wait for load to remove it to prevent script error
12266 window[trans.cb] = function(){
12267 window[trans.cb] = undefined;
12269 delete window[trans.cb];
12276 handleResponse : function(o, trans){
12277 this.trans = false;
12278 this.destroyTrans(trans, true);
12281 result = trans.reader.readRecords(o);
12283 this.fireEvent("loadexception", this, o, trans.arg, e);
12284 trans.callback.call(trans.scope||window, null, trans.arg, false);
12287 this.fireEvent("load", this, o, trans.arg);
12288 trans.callback.call(trans.scope||window, result, trans.arg, true);
12292 handleFailure : function(trans){
12293 this.trans = false;
12294 this.destroyTrans(trans, false);
12295 this.fireEvent("loadexception", this, null, trans.arg);
12296 trans.callback.call(trans.scope||window, null, trans.arg, false);
12300 * Ext JS Library 1.1.1
12301 * Copyright(c) 2006-2007, Ext JS, LLC.
12303 * Originally Released Under LGPL - original licence link has changed is not relivant.
12306 * <script type="text/javascript">
12310 * @class Roo.data.JsonReader
12311 * @extends Roo.data.DataReader
12312 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12313 * based on mappings in a provided Roo.data.Record constructor.
12315 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12316 * in the reply previously.
12321 var RecordDef = Roo.data.Record.create([
12322 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12323 {name: 'occupation'} // This field will use "occupation" as the mapping.
12325 var myReader = new Roo.data.JsonReader({
12326 totalProperty: "results", // The property which contains the total dataset size (optional)
12327 root: "rows", // The property which contains an Array of row objects
12328 id: "id" // The property within each row object that provides an ID for the record (optional)
12332 * This would consume a JSON file like this:
12334 { 'results': 2, 'rows': [
12335 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12336 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12339 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12340 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12341 * paged from the remote server.
12342 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12343 * @cfg {String} root name of the property which contains the Array of row objects.
12344 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12345 * @cfg {Array} fields Array of field definition objects
12347 * Create a new JsonReader
12348 * @param {Object} meta Metadata configuration options
12349 * @param {Object} recordType Either an Array of field definition objects,
12350 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12352 Roo.data.JsonReader = function(meta, recordType){
12355 // set some defaults:
12356 Roo.applyIf(meta, {
12357 totalProperty: 'total',
12358 successProperty : 'success',
12363 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12365 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12368 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12369 * Used by Store query builder to append _requestMeta to params.
12372 metaFromRemote : false,
12374 * This method is only used by a DataProxy which has retrieved data from a remote server.
12375 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12376 * @return {Object} data A data block which is used by an Roo.data.Store object as
12377 * a cache of Roo.data.Records.
12379 read : function(response){
12380 var json = response.responseText;
12382 var o = /* eval:var:o */ eval("("+json+")");
12384 throw {message: "JsonReader.read: Json object not found"};
12390 this.metaFromRemote = true;
12391 this.meta = o.metaData;
12392 this.recordType = Roo.data.Record.create(o.metaData.fields);
12393 this.onMetaChange(this.meta, this.recordType, o);
12395 return this.readRecords(o);
12398 // private function a store will implement
12399 onMetaChange : function(meta, recordType, o){
12406 simpleAccess: function(obj, subsc) {
12413 getJsonAccessor: function(){
12415 return function(expr) {
12417 return(re.test(expr))
12418 ? new Function("obj", "return obj." + expr)
12423 return Roo.emptyFn;
12428 * Create a data block containing Roo.data.Records from an XML document.
12429 * @param {Object} o An object which contains an Array of row objects in the property specified
12430 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12431 * which contains the total size of the dataset.
12432 * @return {Object} data A data block which is used by an Roo.data.Store object as
12433 * a cache of Roo.data.Records.
12435 readRecords : function(o){
12437 * After any data loads, the raw JSON data is available for further custom processing.
12441 var s = this.meta, Record = this.recordType,
12442 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12444 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12446 if(s.totalProperty) {
12447 this.getTotal = this.getJsonAccessor(s.totalProperty);
12449 if(s.successProperty) {
12450 this.getSuccess = this.getJsonAccessor(s.successProperty);
12452 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12454 var g = this.getJsonAccessor(s.id);
12455 this.getId = function(rec) {
12457 return (r === undefined || r === "") ? null : r;
12460 this.getId = function(){return null;};
12463 for(var jj = 0; jj < fl; jj++){
12465 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12466 this.ef[jj] = this.getJsonAccessor(map);
12470 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12471 if(s.totalProperty){
12472 var vt = parseInt(this.getTotal(o), 10);
12477 if(s.successProperty){
12478 var vs = this.getSuccess(o);
12479 if(vs === false || vs === 'false'){
12484 for(var i = 0; i < c; i++){
12487 var id = this.getId(n);
12488 for(var j = 0; j < fl; j++){
12490 var v = this.ef[j](n);
12492 Roo.log('missing convert for ' + f.name);
12496 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12498 var record = new Record(values, id);
12500 records[i] = record;
12506 totalRecords : totalRecords
12511 * Ext JS Library 1.1.1
12512 * Copyright(c) 2006-2007, Ext JS, LLC.
12514 * Originally Released Under LGPL - original licence link has changed is not relivant.
12517 * <script type="text/javascript">
12521 * @class Roo.data.ArrayReader
12522 * @extends Roo.data.DataReader
12523 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12524 * Each element of that Array represents a row of data fields. The
12525 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12526 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12530 var RecordDef = Roo.data.Record.create([
12531 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12532 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12534 var myReader = new Roo.data.ArrayReader({
12535 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12539 * This would consume an Array like this:
12541 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12543 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12545 * Create a new JsonReader
12546 * @param {Object} meta Metadata configuration options.
12547 * @param {Object} recordType Either an Array of field definition objects
12548 * as specified to {@link Roo.data.Record#create},
12549 * or an {@link Roo.data.Record} object
12550 * created using {@link Roo.data.Record#create}.
12552 Roo.data.ArrayReader = function(meta, recordType){
12553 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12556 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12558 * Create a data block containing Roo.data.Records from an XML document.
12559 * @param {Object} o An Array of row objects which represents the dataset.
12560 * @return {Object} data A data block which is used by an Roo.data.Store object as
12561 * a cache of Roo.data.Records.
12563 readRecords : function(o){
12564 var sid = this.meta ? this.meta.id : null;
12565 var recordType = this.recordType, fields = recordType.prototype.fields;
12568 for(var i = 0; i < root.length; i++){
12571 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12572 for(var j = 0, jlen = fields.length; j < jlen; j++){
12573 var f = fields.items[j];
12574 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12575 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12577 values[f.name] = v;
12579 var record = new recordType(values, id);
12581 records[records.length] = record;
12585 totalRecords : records.length
12594 * @class Roo.bootstrap.ComboBox
12595 * @extends Roo.bootstrap.TriggerField
12596 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12597 * @cfg {Boolean} append (true|false) default false
12598 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12599 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12600 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12601 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12602 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12603 * @cfg {Boolean} animate default true
12604 * @cfg {Boolean} emptyResultText only for touch device
12605 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12606 * @cfg {String} emptyTitle default ''
12608 * Create a new ComboBox.
12609 * @param {Object} config Configuration options
12611 Roo.bootstrap.ComboBox = function(config){
12612 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12616 * Fires when the dropdown list is expanded
12617 * @param {Roo.bootstrap.ComboBox} combo This combo box
12622 * Fires when the dropdown list is collapsed
12623 * @param {Roo.bootstrap.ComboBox} combo This combo box
12627 * @event beforeselect
12628 * Fires before a list item is selected. Return false to cancel the selection.
12629 * @param {Roo.bootstrap.ComboBox} combo This combo box
12630 * @param {Roo.data.Record} record The data record returned from the underlying store
12631 * @param {Number} index The index of the selected item in the dropdown list
12633 'beforeselect' : true,
12636 * Fires when a list item is selected
12637 * @param {Roo.bootstrap.ComboBox} combo This combo box
12638 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12639 * @param {Number} index The index of the selected item in the dropdown list
12643 * @event beforequery
12644 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12645 * The event object passed has these properties:
12646 * @param {Roo.bootstrap.ComboBox} combo This combo box
12647 * @param {String} query The query
12648 * @param {Boolean} forceAll true to force "all" query
12649 * @param {Boolean} cancel true to cancel the query
12650 * @param {Object} e The query event object
12652 'beforequery': true,
12655 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12656 * @param {Roo.bootstrap.ComboBox} combo This combo box
12661 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12662 * @param {Roo.bootstrap.ComboBox} combo This combo box
12663 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12668 * Fires when the remove value from the combobox array
12669 * @param {Roo.bootstrap.ComboBox} combo This combo box
12673 * @event afterremove
12674 * Fires when the remove value from the combobox array
12675 * @param {Roo.bootstrap.ComboBox} combo This combo box
12677 'afterremove' : true,
12679 * @event specialfilter
12680 * Fires when specialfilter
12681 * @param {Roo.bootstrap.ComboBox} combo This combo box
12683 'specialfilter' : true,
12686 * Fires when tick the element
12687 * @param {Roo.bootstrap.ComboBox} combo This combo box
12691 * @event touchviewdisplay
12692 * Fires when touch view require special display (default is using displayField)
12693 * @param {Roo.bootstrap.ComboBox} combo This combo box
12694 * @param {Object} cfg set html .
12696 'touchviewdisplay' : true
12701 this.tickItems = [];
12703 this.selectedIndex = -1;
12704 if(this.mode == 'local'){
12705 if(config.queryDelay === undefined){
12706 this.queryDelay = 10;
12708 if(config.minChars === undefined){
12714 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12717 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12718 * rendering into an Roo.Editor, defaults to false)
12721 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12722 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12725 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12728 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12729 * the dropdown list (defaults to undefined, with no header element)
12733 * @cfg {String/Roo.Template} tpl The template to use to render the output
12737 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12739 listWidth: undefined,
12741 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12742 * mode = 'remote' or 'text' if mode = 'local')
12744 displayField: undefined,
12747 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12748 * mode = 'remote' or 'value' if mode = 'local').
12749 * Note: use of a valueField requires the user make a selection
12750 * in order for a value to be mapped.
12752 valueField: undefined,
12754 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12759 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12760 * field's data value (defaults to the underlying DOM element's name)
12762 hiddenName: undefined,
12764 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12768 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12770 selectedClass: 'active',
12773 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12777 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12778 * anchor positions (defaults to 'tl-bl')
12780 listAlign: 'tl-bl?',
12782 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12786 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
12787 * query specified by the allQuery config option (defaults to 'query')
12789 triggerAction: 'query',
12791 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12792 * (defaults to 4, does not apply if editable = false)
12796 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12797 * delay (typeAheadDelay) if it matches a known value (defaults to false)
12801 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12802 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12806 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12807 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
12811 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
12812 * when editable = true (defaults to false)
12814 selectOnFocus:false,
12816 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12818 queryParam: 'query',
12820 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
12821 * when mode = 'remote' (defaults to 'Loading...')
12823 loadingText: 'Loading...',
12825 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12829 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12833 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12834 * traditional select (defaults to true)
12838 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12842 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12846 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12847 * listWidth has a higher value)
12851 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12852 * allow the user to set arbitrary text into the field (defaults to false)
12854 forceSelection:false,
12856 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12857 * if typeAhead = true (defaults to 250)
12859 typeAheadDelay : 250,
12861 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12862 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12864 valueNotFoundText : undefined,
12866 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12868 blockFocus : false,
12871 * @cfg {Boolean} disableClear Disable showing of clear button.
12873 disableClear : false,
12875 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
12877 alwaysQuery : false,
12880 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
12885 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12887 invalidClass : "has-warning",
12890 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12892 validClass : "has-success",
12895 * @cfg {Boolean} specialFilter (true|false) special filter default false
12897 specialFilter : false,
12900 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12902 mobileTouchView : true,
12905 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12907 useNativeIOS : false,
12909 ios_options : false,
12921 btnPosition : 'right',
12922 triggerList : true,
12923 showToggleBtn : true,
12925 emptyResultText: 'Empty',
12926 triggerText : 'Select',
12929 // element that contains real text value.. (when hidden is used..)
12931 getAutoCreate : function()
12936 * Render classic select for iso
12939 if(Roo.isIOS && this.useNativeIOS){
12940 cfg = this.getAutoCreateNativeIOS();
12948 if(Roo.isTouch && this.mobileTouchView){
12949 cfg = this.getAutoCreateTouchView();
12956 if(!this.tickable){
12957 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12962 * ComboBox with tickable selections
12965 var align = this.labelAlign || this.parentLabelAlign();
12968 cls : 'form-group roo-combobox-tickable' //input-group
12971 var btn_text_select = '';
12972 var btn_text_done = '';
12973 var btn_text_cancel = '';
12975 if (this.btn_text_show) {
12976 btn_text_select = 'Select';
12977 btn_text_done = 'Done';
12978 btn_text_cancel = 'Cancel';
12983 cls : 'tickable-buttons',
12988 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
12989 //html : this.triggerText
12990 html: btn_text_select
12996 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
12998 html: btn_text_done
13004 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13006 html: btn_text_cancel
13012 buttons.cn.unshift({
13014 cls: 'roo-select2-search-field-input'
13020 Roo.each(buttons.cn, function(c){
13022 c.cls += ' btn-' + _this.size;
13025 if (_this.disabled) {
13036 cls: 'form-hidden-field'
13040 cls: 'roo-select2-choices',
13044 cls: 'roo-select2-search-field',
13055 cls: 'roo-select2-container input-group roo-select2-container-multi',
13060 // cls: 'typeahead typeahead-long dropdown-menu',
13061 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13066 if(this.hasFeedback && !this.allowBlank){
13070 cls: 'glyphicon form-control-feedback'
13073 combobox.cn.push(feedback);
13077 if (align ==='left' && this.fieldLabel.length) {
13079 cfg.cls += ' roo-form-group-label-left';
13084 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13085 tooltip : 'This field is required'
13090 cls : 'control-label',
13091 html : this.fieldLabel
13103 var labelCfg = cfg.cn[1];
13104 var contentCfg = cfg.cn[2];
13107 if(this.indicatorpos == 'right'){
13113 cls : 'control-label',
13117 html : this.fieldLabel
13121 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13122 tooltip : 'This field is required'
13137 labelCfg = cfg.cn[0];
13138 contentCfg = cfg.cn[1];
13142 if(this.labelWidth > 12){
13143 labelCfg.style = "width: " + this.labelWidth + 'px';
13146 if(this.labelWidth < 13 && this.labelmd == 0){
13147 this.labelmd = this.labelWidth;
13150 if(this.labellg > 0){
13151 labelCfg.cls += ' col-lg-' + this.labellg;
13152 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13155 if(this.labelmd > 0){
13156 labelCfg.cls += ' col-md-' + this.labelmd;
13157 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13160 if(this.labelsm > 0){
13161 labelCfg.cls += ' col-sm-' + this.labelsm;
13162 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13165 if(this.labelxs > 0){
13166 labelCfg.cls += ' col-xs-' + this.labelxs;
13167 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13171 } else if ( this.fieldLabel.length) {
13172 // Roo.log(" label");
13176 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13177 tooltip : 'This field is required'
13181 //cls : 'input-group-addon',
13182 html : this.fieldLabel
13187 if(this.indicatorpos == 'right'){
13191 //cls : 'input-group-addon',
13192 html : this.fieldLabel
13196 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13197 tooltip : 'This field is required'
13206 // Roo.log(" no label && no align");
13213 ['xs','sm','md','lg'].map(function(size){
13214 if (settings[size]) {
13215 cfg.cls += ' col-' + size + '-' + settings[size];
13223 _initEventsCalled : false,
13226 initEvents: function()
13228 if (this._initEventsCalled) { // as we call render... prevent looping...
13231 this._initEventsCalled = true;
13234 throw "can not find store for combo";
13237 this.indicator = this.indicatorEl();
13239 this.store = Roo.factory(this.store, Roo.data);
13240 this.store.parent = this;
13242 // if we are building from html. then this element is so complex, that we can not really
13243 // use the rendered HTML.
13244 // so we have to trash and replace the previous code.
13245 if (Roo.XComponent.build_from_html) {
13246 // remove this element....
13247 var e = this.el.dom, k=0;
13248 while (e ) { e = e.previousSibling; ++k;}
13253 this.rendered = false;
13255 this.render(this.parent().getChildContainer(true), k);
13258 if(Roo.isIOS && this.useNativeIOS){
13259 this.initIOSView();
13267 if(Roo.isTouch && this.mobileTouchView){
13268 this.initTouchView();
13273 this.initTickableEvents();
13277 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13279 if(this.hiddenName){
13281 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13283 this.hiddenField.dom.value =
13284 this.hiddenValue !== undefined ? this.hiddenValue :
13285 this.value !== undefined ? this.value : '';
13287 // prevent input submission
13288 this.el.dom.removeAttribute('name');
13289 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13294 // this.el.dom.setAttribute('autocomplete', 'off');
13297 var cls = 'x-combo-list';
13299 //this.list = new Roo.Layer({
13300 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13306 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13307 _this.list.setWidth(lw);
13310 this.list.on('mouseover', this.onViewOver, this);
13311 this.list.on('mousemove', this.onViewMove, this);
13312 this.list.on('scroll', this.onViewScroll, this);
13315 this.list.swallowEvent('mousewheel');
13316 this.assetHeight = 0;
13319 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13320 this.assetHeight += this.header.getHeight();
13323 this.innerList = this.list.createChild({cls:cls+'-inner'});
13324 this.innerList.on('mouseover', this.onViewOver, this);
13325 this.innerList.on('mousemove', this.onViewMove, this);
13326 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13328 if(this.allowBlank && !this.pageSize && !this.disableClear){
13329 this.footer = this.list.createChild({cls:cls+'-ft'});
13330 this.pageTb = new Roo.Toolbar(this.footer);
13334 this.footer = this.list.createChild({cls:cls+'-ft'});
13335 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13336 {pageSize: this.pageSize});
13340 if (this.pageTb && this.allowBlank && !this.disableClear) {
13342 this.pageTb.add(new Roo.Toolbar.Fill(), {
13343 cls: 'x-btn-icon x-btn-clear',
13345 handler: function()
13348 _this.clearValue();
13349 _this.onSelect(false, -1);
13354 this.assetHeight += this.footer.getHeight();
13359 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13362 this.view = new Roo.View(this.list, this.tpl, {
13363 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13365 //this.view.wrapEl.setDisplayed(false);
13366 this.view.on('click', this.onViewClick, this);
13369 this.store.on('beforeload', this.onBeforeLoad, this);
13370 this.store.on('load', this.onLoad, this);
13371 this.store.on('loadexception', this.onLoadException, this);
13373 if(this.resizable){
13374 this.resizer = new Roo.Resizable(this.list, {
13375 pinned:true, handles:'se'
13377 this.resizer.on('resize', function(r, w, h){
13378 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13379 this.listWidth = w;
13380 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13381 this.restrictHeight();
13383 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13386 if(!this.editable){
13387 this.editable = true;
13388 this.setEditable(false);
13393 if (typeof(this.events.add.listeners) != 'undefined') {
13395 this.addicon = this.wrap.createChild(
13396 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13398 this.addicon.on('click', function(e) {
13399 this.fireEvent('add', this);
13402 if (typeof(this.events.edit.listeners) != 'undefined') {
13404 this.editicon = this.wrap.createChild(
13405 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13406 if (this.addicon) {
13407 this.editicon.setStyle('margin-left', '40px');
13409 this.editicon.on('click', function(e) {
13411 // we fire even if inothing is selected..
13412 this.fireEvent('edit', this, this.lastData );
13418 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13419 "up" : function(e){
13420 this.inKeyMode = true;
13424 "down" : function(e){
13425 if(!this.isExpanded()){
13426 this.onTriggerClick();
13428 this.inKeyMode = true;
13433 "enter" : function(e){
13434 // this.onViewClick();
13438 if(this.fireEvent("specialkey", this, e)){
13439 this.onViewClick(false);
13445 "esc" : function(e){
13449 "tab" : function(e){
13452 if(this.fireEvent("specialkey", this, e)){
13453 this.onViewClick(false);
13461 doRelay : function(foo, bar, hname){
13462 if(hname == 'down' || this.scope.isExpanded()){
13463 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13472 this.queryDelay = Math.max(this.queryDelay || 10,
13473 this.mode == 'local' ? 10 : 250);
13476 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13478 if(this.typeAhead){
13479 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13481 if(this.editable !== false){
13482 this.inputEl().on("keyup", this.onKeyUp, this);
13484 if(this.forceSelection){
13485 this.inputEl().on('blur', this.doForce, this);
13489 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13490 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13494 initTickableEvents: function()
13498 if(this.hiddenName){
13500 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13502 this.hiddenField.dom.value =
13503 this.hiddenValue !== undefined ? this.hiddenValue :
13504 this.value !== undefined ? this.value : '';
13506 // prevent input submission
13507 this.el.dom.removeAttribute('name');
13508 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13513 // this.list = this.el.select('ul.dropdown-menu',true).first();
13515 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13516 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13517 if(this.triggerList){
13518 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13521 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13522 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13524 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13525 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13527 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13528 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13530 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13531 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13532 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13535 this.cancelBtn.hide();
13540 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13541 _this.list.setWidth(lw);
13544 this.list.on('mouseover', this.onViewOver, this);
13545 this.list.on('mousemove', this.onViewMove, this);
13547 this.list.on('scroll', this.onViewScroll, this);
13550 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>';
13553 this.view = new Roo.View(this.list, this.tpl, {
13554 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13557 //this.view.wrapEl.setDisplayed(false);
13558 this.view.on('click', this.onViewClick, this);
13562 this.store.on('beforeload', this.onBeforeLoad, this);
13563 this.store.on('load', this.onLoad, this);
13564 this.store.on('loadexception', this.onLoadException, this);
13567 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13568 "up" : function(e){
13569 this.inKeyMode = true;
13573 "down" : function(e){
13574 this.inKeyMode = true;
13578 "enter" : function(e){
13579 if(this.fireEvent("specialkey", this, e)){
13580 this.onViewClick(false);
13586 "esc" : function(e){
13587 this.onTickableFooterButtonClick(e, false, false);
13590 "tab" : function(e){
13591 this.fireEvent("specialkey", this, e);
13593 this.onTickableFooterButtonClick(e, false, false);
13600 doRelay : function(e, fn, key){
13601 if(this.scope.isExpanded()){
13602 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13611 this.queryDelay = Math.max(this.queryDelay || 10,
13612 this.mode == 'local' ? 10 : 250);
13615 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13617 if(this.typeAhead){
13618 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13621 if(this.editable !== false){
13622 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13625 this.indicator = this.indicatorEl();
13627 if(this.indicator){
13628 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13629 this.indicator.hide();
13634 onDestroy : function(){
13636 this.view.setStore(null);
13637 this.view.el.removeAllListeners();
13638 this.view.el.remove();
13639 this.view.purgeListeners();
13642 this.list.dom.innerHTML = '';
13646 this.store.un('beforeload', this.onBeforeLoad, this);
13647 this.store.un('load', this.onLoad, this);
13648 this.store.un('loadexception', this.onLoadException, this);
13650 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13654 fireKey : function(e){
13655 if(e.isNavKeyPress() && !this.list.isVisible()){
13656 this.fireEvent("specialkey", this, e);
13661 onResize: function(w, h){
13662 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13664 // if(typeof w != 'number'){
13665 // // we do not handle it!?!?
13668 // var tw = this.trigger.getWidth();
13669 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13670 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13672 // this.inputEl().setWidth( this.adjustWidth('input', x));
13674 // //this.trigger.setStyle('left', x+'px');
13676 // if(this.list && this.listWidth === undefined){
13677 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13678 // this.list.setWidth(lw);
13679 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13687 * Allow or prevent the user from directly editing the field text. If false is passed,
13688 * the user will only be able to select from the items defined in the dropdown list. This method
13689 * is the runtime equivalent of setting the 'editable' config option at config time.
13690 * @param {Boolean} value True to allow the user to directly edit the field text
13692 setEditable : function(value){
13693 if(value == this.editable){
13696 this.editable = value;
13698 this.inputEl().dom.setAttribute('readOnly', true);
13699 this.inputEl().on('mousedown', this.onTriggerClick, this);
13700 this.inputEl().addClass('x-combo-noedit');
13702 this.inputEl().dom.setAttribute('readOnly', false);
13703 this.inputEl().un('mousedown', this.onTriggerClick, this);
13704 this.inputEl().removeClass('x-combo-noedit');
13710 onBeforeLoad : function(combo,opts){
13711 if(!this.hasFocus){
13715 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13717 this.restrictHeight();
13718 this.selectedIndex = -1;
13722 onLoad : function(){
13724 this.hasQuery = false;
13726 if(!this.hasFocus){
13730 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13731 this.loading.hide();
13734 if(this.store.getCount() > 0){
13737 this.restrictHeight();
13738 if(this.lastQuery == this.allQuery){
13739 if(this.editable && !this.tickable){
13740 this.inputEl().dom.select();
13744 !this.selectByValue(this.value, true) &&
13747 !this.store.lastOptions ||
13748 typeof(this.store.lastOptions.add) == 'undefined' ||
13749 this.store.lastOptions.add != true
13752 this.select(0, true);
13755 if(this.autoFocus){
13758 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13759 this.taTask.delay(this.typeAheadDelay);
13763 this.onEmptyResults();
13769 onLoadException : function()
13771 this.hasQuery = false;
13773 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13774 this.loading.hide();
13777 if(this.tickable && this.editable){
13782 // only causes errors at present
13783 //Roo.log(this.store.reader.jsonData);
13784 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13786 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13792 onTypeAhead : function(){
13793 if(this.store.getCount() > 0){
13794 var r = this.store.getAt(0);
13795 var newValue = r.data[this.displayField];
13796 var len = newValue.length;
13797 var selStart = this.getRawValue().length;
13799 if(selStart != len){
13800 this.setRawValue(newValue);
13801 this.selectText(selStart, newValue.length);
13807 onSelect : function(record, index){
13809 if(this.fireEvent('beforeselect', this, record, index) !== false){
13811 this.setFromData(index > -1 ? record.data : false);
13814 this.fireEvent('select', this, record, index);
13819 * Returns the currently selected field value or empty string if no value is set.
13820 * @return {String} value The selected value
13822 getValue : function()
13824 if(Roo.isIOS && this.useNativeIOS){
13825 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13829 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13832 if(this.valueField){
13833 return typeof this.value != 'undefined' ? this.value : '';
13835 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13839 getRawValue : function()
13841 if(Roo.isIOS && this.useNativeIOS){
13842 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13845 var v = this.inputEl().getValue();
13851 * Clears any text/value currently set in the field
13853 clearValue : function(){
13855 if(this.hiddenField){
13856 this.hiddenField.dom.value = '';
13859 this.setRawValue('');
13860 this.lastSelectionText = '';
13861 this.lastData = false;
13863 var close = this.closeTriggerEl();
13874 * Sets the specified value into the field. If the value finds a match, the corresponding record text
13875 * will be displayed in the field. If the value does not match the data value of an existing item,
13876 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13877 * Otherwise the field will be blank (although the value will still be set).
13878 * @param {String} value The value to match
13880 setValue : function(v)
13882 if(Roo.isIOS && this.useNativeIOS){
13883 this.setIOSValue(v);
13893 if(this.valueField){
13894 var r = this.findRecord(this.valueField, v);
13896 text = r.data[this.displayField];
13897 }else if(this.valueNotFoundText !== undefined){
13898 text = this.valueNotFoundText;
13901 this.lastSelectionText = text;
13902 if(this.hiddenField){
13903 this.hiddenField.dom.value = v;
13905 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13908 var close = this.closeTriggerEl();
13911 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13917 * @property {Object} the last set data for the element
13922 * Sets the value of the field based on a object which is related to the record format for the store.
13923 * @param {Object} value the value to set as. or false on reset?
13925 setFromData : function(o){
13932 var dv = ''; // display value
13933 var vv = ''; // value value..
13935 if (this.displayField) {
13936 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13938 // this is an error condition!!!
13939 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
13942 if(this.valueField){
13943 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13946 var close = this.closeTriggerEl();
13949 if(dv.length || vv * 1 > 0){
13951 this.blockFocus=true;
13957 if(this.hiddenField){
13958 this.hiddenField.dom.value = vv;
13960 this.lastSelectionText = dv;
13961 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13965 // no hidden field.. - we store the value in 'value', but still display
13966 // display field!!!!
13967 this.lastSelectionText = dv;
13968 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13975 reset : function(){
13976 // overridden so that last data is reset..
13983 this.setValue(this.originalValue);
13984 //this.clearInvalid();
13985 this.lastData = false;
13987 this.view.clearSelections();
13993 findRecord : function(prop, value){
13995 if(this.store.getCount() > 0){
13996 this.store.each(function(r){
13997 if(r.data[prop] == value){
14007 getName: function()
14009 // returns hidden if it's set..
14010 if (!this.rendered) {return ''};
14011 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14015 onViewMove : function(e, t){
14016 this.inKeyMode = false;
14020 onViewOver : function(e, t){
14021 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14024 var item = this.view.findItemFromChild(t);
14027 var index = this.view.indexOf(item);
14028 this.select(index, false);
14033 onViewClick : function(view, doFocus, el, e)
14035 var index = this.view.getSelectedIndexes()[0];
14037 var r = this.store.getAt(index);
14041 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14048 Roo.each(this.tickItems, function(v,k){
14050 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14052 _this.tickItems.splice(k, 1);
14054 if(typeof(e) == 'undefined' && view == false){
14055 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14067 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14068 this.tickItems.push(r.data);
14071 if(typeof(e) == 'undefined' && view == false){
14072 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14079 this.onSelect(r, index);
14081 if(doFocus !== false && !this.blockFocus){
14082 this.inputEl().focus();
14087 restrictHeight : function(){
14088 //this.innerList.dom.style.height = '';
14089 //var inner = this.innerList.dom;
14090 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14091 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14092 //this.list.beginUpdate();
14093 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14094 this.list.alignTo(this.inputEl(), this.listAlign);
14095 this.list.alignTo(this.inputEl(), this.listAlign);
14096 //this.list.endUpdate();
14100 onEmptyResults : function(){
14102 if(this.tickable && this.editable){
14103 this.hasFocus = false;
14104 this.restrictHeight();
14112 * Returns true if the dropdown list is expanded, else false.
14114 isExpanded : function(){
14115 return this.list.isVisible();
14119 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14120 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14121 * @param {String} value The data value of the item to select
14122 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14123 * selected item if it is not currently in view (defaults to true)
14124 * @return {Boolean} True if the value matched an item in the list, else false
14126 selectByValue : function(v, scrollIntoView){
14127 if(v !== undefined && v !== null){
14128 var r = this.findRecord(this.valueField || this.displayField, v);
14130 this.select(this.store.indexOf(r), scrollIntoView);
14138 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14139 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14140 * @param {Number} index The zero-based index of the list item to select
14141 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14142 * selected item if it is not currently in view (defaults to true)
14144 select : function(index, scrollIntoView){
14145 this.selectedIndex = index;
14146 this.view.select(index);
14147 if(scrollIntoView !== false){
14148 var el = this.view.getNode(index);
14150 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14153 this.list.scrollChildIntoView(el, false);
14159 selectNext : function(){
14160 var ct = this.store.getCount();
14162 if(this.selectedIndex == -1){
14164 }else if(this.selectedIndex < ct-1){
14165 this.select(this.selectedIndex+1);
14171 selectPrev : function(){
14172 var ct = this.store.getCount();
14174 if(this.selectedIndex == -1){
14176 }else if(this.selectedIndex != 0){
14177 this.select(this.selectedIndex-1);
14183 onKeyUp : function(e){
14184 if(this.editable !== false && !e.isSpecialKey()){
14185 this.lastKey = e.getKey();
14186 this.dqTask.delay(this.queryDelay);
14191 validateBlur : function(){
14192 return !this.list || !this.list.isVisible();
14196 initQuery : function(){
14198 var v = this.getRawValue();
14200 if(this.tickable && this.editable){
14201 v = this.tickableInputEl().getValue();
14208 doForce : function(){
14209 if(this.inputEl().dom.value.length > 0){
14210 this.inputEl().dom.value =
14211 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14217 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14218 * query allowing the query action to be canceled if needed.
14219 * @param {String} query The SQL query to execute
14220 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14221 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14222 * saved in the current store (defaults to false)
14224 doQuery : function(q, forceAll){
14226 if(q === undefined || q === null){
14231 forceAll: forceAll,
14235 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14240 forceAll = qe.forceAll;
14241 if(forceAll === true || (q.length >= this.minChars)){
14243 this.hasQuery = true;
14245 if(this.lastQuery != q || this.alwaysQuery){
14246 this.lastQuery = q;
14247 if(this.mode == 'local'){
14248 this.selectedIndex = -1;
14250 this.store.clearFilter();
14253 if(this.specialFilter){
14254 this.fireEvent('specialfilter', this);
14259 this.store.filter(this.displayField, q);
14262 this.store.fireEvent("datachanged", this.store);
14269 this.store.baseParams[this.queryParam] = q;
14271 var options = {params : this.getParams(q)};
14274 options.add = true;
14275 options.params.start = this.page * this.pageSize;
14278 this.store.load(options);
14281 * this code will make the page width larger, at the beginning, the list not align correctly,
14282 * we should expand the list on onLoad
14283 * so command out it
14288 this.selectedIndex = -1;
14293 this.loadNext = false;
14297 getParams : function(q){
14299 //p[this.queryParam] = q;
14303 p.limit = this.pageSize;
14309 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14311 collapse : function(){
14312 if(!this.isExpanded()){
14318 this.hasFocus = false;
14322 this.cancelBtn.hide();
14323 this.trigger.show();
14326 this.tickableInputEl().dom.value = '';
14327 this.tickableInputEl().blur();
14332 Roo.get(document).un('mousedown', this.collapseIf, this);
14333 Roo.get(document).un('mousewheel', this.collapseIf, this);
14334 if (!this.editable) {
14335 Roo.get(document).un('keydown', this.listKeyPress, this);
14337 this.fireEvent('collapse', this);
14343 collapseIf : function(e){
14344 var in_combo = e.within(this.el);
14345 var in_list = e.within(this.list);
14346 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14348 if (in_combo || in_list || is_list) {
14349 //e.stopPropagation();
14354 this.onTickableFooterButtonClick(e, false, false);
14362 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14364 expand : function(){
14366 if(this.isExpanded() || !this.hasFocus){
14370 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14371 this.list.setWidth(lw);
14377 this.restrictHeight();
14381 this.tickItems = Roo.apply([], this.item);
14384 this.cancelBtn.show();
14385 this.trigger.hide();
14388 this.tickableInputEl().focus();
14393 Roo.get(document).on('mousedown', this.collapseIf, this);
14394 Roo.get(document).on('mousewheel', this.collapseIf, this);
14395 if (!this.editable) {
14396 Roo.get(document).on('keydown', this.listKeyPress, this);
14399 this.fireEvent('expand', this);
14403 // Implements the default empty TriggerField.onTriggerClick function
14404 onTriggerClick : function(e)
14406 Roo.log('trigger click');
14408 if(this.disabled || !this.triggerList){
14413 this.loadNext = false;
14415 if(this.isExpanded()){
14417 if (!this.blockFocus) {
14418 this.inputEl().focus();
14422 this.hasFocus = true;
14423 if(this.triggerAction == 'all') {
14424 this.doQuery(this.allQuery, true);
14426 this.doQuery(this.getRawValue());
14428 if (!this.blockFocus) {
14429 this.inputEl().focus();
14434 onTickableTriggerClick : function(e)
14441 this.loadNext = false;
14442 this.hasFocus = true;
14444 if(this.triggerAction == 'all') {
14445 this.doQuery(this.allQuery, true);
14447 this.doQuery(this.getRawValue());
14451 onSearchFieldClick : function(e)
14453 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14454 this.onTickableFooterButtonClick(e, false, false);
14458 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14463 this.loadNext = false;
14464 this.hasFocus = true;
14466 if(this.triggerAction == 'all') {
14467 this.doQuery(this.allQuery, true);
14469 this.doQuery(this.getRawValue());
14473 listKeyPress : function(e)
14475 //Roo.log('listkeypress');
14476 // scroll to first matching element based on key pres..
14477 if (e.isSpecialKey()) {
14480 var k = String.fromCharCode(e.getKey()).toUpperCase();
14483 var csel = this.view.getSelectedNodes();
14484 var cselitem = false;
14486 var ix = this.view.indexOf(csel[0]);
14487 cselitem = this.store.getAt(ix);
14488 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14494 this.store.each(function(v) {
14496 // start at existing selection.
14497 if (cselitem.id == v.id) {
14503 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14504 match = this.store.indexOf(v);
14510 if (match === false) {
14511 return true; // no more action?
14514 this.view.select(match);
14515 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14516 sn.scrollIntoView(sn.dom.parentNode, false);
14519 onViewScroll : function(e, t){
14521 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){
14525 this.hasQuery = true;
14527 this.loading = this.list.select('.loading', true).first();
14529 if(this.loading === null){
14530 this.list.createChild({
14532 cls: 'loading roo-select2-more-results roo-select2-active',
14533 html: 'Loading more results...'
14536 this.loading = this.list.select('.loading', true).first();
14538 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14540 this.loading.hide();
14543 this.loading.show();
14548 this.loadNext = true;
14550 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14555 addItem : function(o)
14557 var dv = ''; // display value
14559 if (this.displayField) {
14560 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14562 // this is an error condition!!!
14563 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14570 var choice = this.choices.createChild({
14572 cls: 'roo-select2-search-choice',
14581 cls: 'roo-select2-search-choice-close fa fa-times',
14586 }, this.searchField);
14588 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14590 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14598 this.inputEl().dom.value = '';
14603 onRemoveItem : function(e, _self, o)
14605 e.preventDefault();
14607 this.lastItem = Roo.apply([], this.item);
14609 var index = this.item.indexOf(o.data) * 1;
14612 Roo.log('not this item?!');
14616 this.item.splice(index, 1);
14621 this.fireEvent('remove', this, e);
14627 syncValue : function()
14629 if(!this.item.length){
14636 Roo.each(this.item, function(i){
14637 if(_this.valueField){
14638 value.push(i[_this.valueField]);
14645 this.value = value.join(',');
14647 if(this.hiddenField){
14648 this.hiddenField.dom.value = this.value;
14651 this.store.fireEvent("datachanged", this.store);
14656 clearItem : function()
14658 if(!this.multiple){
14664 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14672 if(this.tickable && !Roo.isTouch){
14673 this.view.refresh();
14677 inputEl: function ()
14679 if(Roo.isIOS && this.useNativeIOS){
14680 return this.el.select('select.roo-ios-select', true).first();
14683 if(Roo.isTouch && this.mobileTouchView){
14684 return this.el.select('input.form-control',true).first();
14688 return this.searchField;
14691 return this.el.select('input.form-control',true).first();
14694 onTickableFooterButtonClick : function(e, btn, el)
14696 e.preventDefault();
14698 this.lastItem = Roo.apply([], this.item);
14700 if(btn && btn.name == 'cancel'){
14701 this.tickItems = Roo.apply([], this.item);
14710 Roo.each(this.tickItems, function(o){
14718 validate : function()
14720 if(this.getVisibilityEl().hasClass('hidden')){
14724 var v = this.getRawValue();
14727 v = this.getValue();
14730 if(this.disabled || this.allowBlank || v.length){
14735 this.markInvalid();
14739 tickableInputEl : function()
14741 if(!this.tickable || !this.editable){
14742 return this.inputEl();
14745 return this.inputEl().select('.roo-select2-search-field-input', true).first();
14749 getAutoCreateTouchView : function()
14754 cls: 'form-group' //input-group
14760 type : this.inputType,
14761 cls : 'form-control x-combo-noedit',
14762 autocomplete: 'new-password',
14763 placeholder : this.placeholder || '',
14768 input.name = this.name;
14772 input.cls += ' input-' + this.size;
14775 if (this.disabled) {
14776 input.disabled = true;
14787 inputblock.cls += ' input-group';
14789 inputblock.cn.unshift({
14791 cls : 'input-group-addon',
14796 if(this.removable && !this.multiple){
14797 inputblock.cls += ' roo-removable';
14799 inputblock.cn.push({
14802 cls : 'roo-combo-removable-btn close'
14806 if(this.hasFeedback && !this.allowBlank){
14808 inputblock.cls += ' has-feedback';
14810 inputblock.cn.push({
14812 cls: 'glyphicon form-control-feedback'
14819 inputblock.cls += (this.before) ? '' : ' input-group';
14821 inputblock.cn.push({
14823 cls : 'input-group-addon',
14834 cls: 'form-hidden-field'
14848 cls: 'form-hidden-field'
14852 cls: 'roo-select2-choices',
14856 cls: 'roo-select2-search-field',
14869 cls: 'roo-select2-container input-group roo-touchview-combobox ',
14875 if(!this.multiple && this.showToggleBtn){
14882 if (this.caret != false) {
14885 cls: 'fa fa-' + this.caret
14892 cls : 'input-group-addon btn dropdown-toggle',
14897 cls: 'combobox-clear',
14911 combobox.cls += ' roo-select2-container-multi';
14914 var align = this.labelAlign || this.parentLabelAlign();
14916 if (align ==='left' && this.fieldLabel.length) {
14921 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14922 tooltip : 'This field is required'
14926 cls : 'control-label',
14927 html : this.fieldLabel
14938 var labelCfg = cfg.cn[1];
14939 var contentCfg = cfg.cn[2];
14942 if(this.indicatorpos == 'right'){
14947 cls : 'control-label',
14951 html : this.fieldLabel
14955 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14956 tooltip : 'This field is required'
14969 labelCfg = cfg.cn[0];
14970 contentCfg = cfg.cn[1];
14975 if(this.labelWidth > 12){
14976 labelCfg.style = "width: " + this.labelWidth + 'px';
14979 if(this.labelWidth < 13 && this.labelmd == 0){
14980 this.labelmd = this.labelWidth;
14983 if(this.labellg > 0){
14984 labelCfg.cls += ' col-lg-' + this.labellg;
14985 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
14988 if(this.labelmd > 0){
14989 labelCfg.cls += ' col-md-' + this.labelmd;
14990 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
14993 if(this.labelsm > 0){
14994 labelCfg.cls += ' col-sm-' + this.labelsm;
14995 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
14998 if(this.labelxs > 0){
14999 labelCfg.cls += ' col-xs-' + this.labelxs;
15000 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15004 } else if ( this.fieldLabel.length) {
15008 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15009 tooltip : 'This field is required'
15013 cls : 'control-label',
15014 html : this.fieldLabel
15025 if(this.indicatorpos == 'right'){
15029 cls : 'control-label',
15030 html : this.fieldLabel,
15034 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15035 tooltip : 'This field is required'
15052 var settings = this;
15054 ['xs','sm','md','lg'].map(function(size){
15055 if (settings[size]) {
15056 cfg.cls += ' col-' + size + '-' + settings[size];
15063 initTouchView : function()
15065 this.renderTouchView();
15067 this.touchViewEl.on('scroll', function(){
15068 this.el.dom.scrollTop = 0;
15071 this.originalValue = this.getValue();
15073 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15075 this.inputEl().on("click", this.showTouchView, this);
15076 if (this.triggerEl) {
15077 this.triggerEl.on("click", this.showTouchView, this);
15081 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15082 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15084 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15086 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15087 this.store.on('load', this.onTouchViewLoad, this);
15088 this.store.on('loadexception', this.onTouchViewLoadException, this);
15090 if(this.hiddenName){
15092 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15094 this.hiddenField.dom.value =
15095 this.hiddenValue !== undefined ? this.hiddenValue :
15096 this.value !== undefined ? this.value : '';
15098 this.el.dom.removeAttribute('name');
15099 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15103 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15104 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15107 if(this.removable && !this.multiple){
15108 var close = this.closeTriggerEl();
15110 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15111 close.on('click', this.removeBtnClick, this, close);
15115 * fix the bug in Safari iOS8
15117 this.inputEl().on("focus", function(e){
15118 document.activeElement.blur();
15126 renderTouchView : function()
15128 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15129 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15131 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15132 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15134 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15135 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15136 this.touchViewBodyEl.setStyle('overflow', 'auto');
15138 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15139 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15141 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15142 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15146 showTouchView : function()
15152 this.touchViewHeaderEl.hide();
15154 if(this.modalTitle.length){
15155 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15156 this.touchViewHeaderEl.show();
15159 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15160 this.touchViewEl.show();
15162 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15164 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15165 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15167 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15169 if(this.modalTitle.length){
15170 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15173 this.touchViewBodyEl.setHeight(bodyHeight);
15177 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15179 this.touchViewEl.addClass('in');
15182 this.doTouchViewQuery();
15186 hideTouchView : function()
15188 this.touchViewEl.removeClass('in');
15192 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15194 this.touchViewEl.setStyle('display', 'none');
15199 setTouchViewValue : function()
15206 Roo.each(this.tickItems, function(o){
15211 this.hideTouchView();
15214 doTouchViewQuery : function()
15223 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15227 if(!this.alwaysQuery || this.mode == 'local'){
15228 this.onTouchViewLoad();
15235 onTouchViewBeforeLoad : function(combo,opts)
15241 onTouchViewLoad : function()
15243 if(this.store.getCount() < 1){
15244 this.onTouchViewEmptyResults();
15248 this.clearTouchView();
15250 var rawValue = this.getRawValue();
15252 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15254 this.tickItems = [];
15256 this.store.data.each(function(d, rowIndex){
15257 var row = this.touchViewListGroup.createChild(template);
15259 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15260 row.addClass(d.data.cls);
15263 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15266 html : d.data[this.displayField]
15269 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15270 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15273 row.removeClass('selected');
15274 if(!this.multiple && this.valueField &&
15275 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15278 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15279 row.addClass('selected');
15282 if(this.multiple && this.valueField &&
15283 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15287 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15288 this.tickItems.push(d.data);
15291 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15295 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15297 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15299 if(this.modalTitle.length){
15300 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15303 var listHeight = this.touchViewListGroup.getHeight();
15307 if(firstChecked && listHeight > bodyHeight){
15308 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15313 onTouchViewLoadException : function()
15315 this.hideTouchView();
15318 onTouchViewEmptyResults : function()
15320 this.clearTouchView();
15322 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15324 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15328 clearTouchView : function()
15330 this.touchViewListGroup.dom.innerHTML = '';
15333 onTouchViewClick : function(e, el, o)
15335 e.preventDefault();
15338 var rowIndex = o.rowIndex;
15340 var r = this.store.getAt(rowIndex);
15342 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15344 if(!this.multiple){
15345 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15346 c.dom.removeAttribute('checked');
15349 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15351 this.setFromData(r.data);
15353 var close = this.closeTriggerEl();
15359 this.hideTouchView();
15361 this.fireEvent('select', this, r, rowIndex);
15366 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15367 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15368 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15372 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15373 this.addItem(r.data);
15374 this.tickItems.push(r.data);
15378 getAutoCreateNativeIOS : function()
15381 cls: 'form-group' //input-group,
15386 cls : 'roo-ios-select'
15390 combobox.name = this.name;
15393 if (this.disabled) {
15394 combobox.disabled = true;
15397 var settings = this;
15399 ['xs','sm','md','lg'].map(function(size){
15400 if (settings[size]) {
15401 cfg.cls += ' col-' + size + '-' + settings[size];
15411 initIOSView : function()
15413 this.store.on('load', this.onIOSViewLoad, this);
15418 onIOSViewLoad : function()
15420 if(this.store.getCount() < 1){
15424 this.clearIOSView();
15426 if(this.allowBlank) {
15428 var default_text = '-- SELECT --';
15430 if(this.placeholder.length){
15431 default_text = this.placeholder;
15434 if(this.emptyTitle.length){
15435 default_text += ' - ' + this.emptyTitle + ' -';
15438 var opt = this.inputEl().createChild({
15441 html : default_text
15445 o[this.valueField] = 0;
15446 o[this.displayField] = default_text;
15448 this.ios_options.push({
15455 this.store.data.each(function(d, rowIndex){
15459 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15460 html = d.data[this.displayField];
15465 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15466 value = d.data[this.valueField];
15475 if(this.value == d.data[this.valueField]){
15476 option['selected'] = true;
15479 var opt = this.inputEl().createChild(option);
15481 this.ios_options.push({
15488 this.inputEl().on('change', function(){
15489 this.fireEvent('select', this);
15494 clearIOSView: function()
15496 this.inputEl().dom.innerHTML = '';
15498 this.ios_options = [];
15501 setIOSValue: function(v)
15505 if(!this.ios_options){
15509 Roo.each(this.ios_options, function(opts){
15511 opts.el.dom.removeAttribute('selected');
15513 if(opts.data[this.valueField] != v){
15517 opts.el.dom.setAttribute('selected', true);
15523 * @cfg {Boolean} grow
15527 * @cfg {Number} growMin
15531 * @cfg {Number} growMax
15540 Roo.apply(Roo.bootstrap.ComboBox, {
15544 cls: 'modal-header',
15566 cls: 'list-group-item',
15570 cls: 'roo-combobox-list-group-item-value'
15574 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15588 listItemCheckbox : {
15590 cls: 'list-group-item',
15594 cls: 'roo-combobox-list-group-item-value'
15598 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15614 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15619 cls: 'modal-footer',
15627 cls: 'col-xs-6 text-left',
15630 cls: 'btn btn-danger roo-touch-view-cancel',
15636 cls: 'col-xs-6 text-right',
15639 cls: 'btn btn-success roo-touch-view-ok',
15650 Roo.apply(Roo.bootstrap.ComboBox, {
15652 touchViewTemplate : {
15654 cls: 'modal fade roo-combobox-touch-view',
15658 cls: 'modal-dialog',
15659 style : 'position:fixed', // we have to fix position....
15663 cls: 'modal-content',
15665 Roo.bootstrap.ComboBox.header,
15666 Roo.bootstrap.ComboBox.body,
15667 Roo.bootstrap.ComboBox.footer
15676 * Ext JS Library 1.1.1
15677 * Copyright(c) 2006-2007, Ext JS, LLC.
15679 * Originally Released Under LGPL - original licence link has changed is not relivant.
15682 * <script type="text/javascript">
15687 * @extends Roo.util.Observable
15688 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15689 * This class also supports single and multi selection modes. <br>
15690 * Create a data model bound view:
15692 var store = new Roo.data.Store(...);
15694 var view = new Roo.View({
15696 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15698 singleSelect: true,
15699 selectedClass: "ydataview-selected",
15703 // listen for node click?
15704 view.on("click", function(vw, index, node, e){
15705 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15709 dataModel.load("foobar.xml");
15711 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15713 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15714 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15716 * Note: old style constructor is still suported (container, template, config)
15719 * Create a new View
15720 * @param {Object} config The config object
15723 Roo.View = function(config, depreciated_tpl, depreciated_config){
15725 this.parent = false;
15727 if (typeof(depreciated_tpl) == 'undefined') {
15728 // new way.. - universal constructor.
15729 Roo.apply(this, config);
15730 this.el = Roo.get(this.el);
15733 this.el = Roo.get(config);
15734 this.tpl = depreciated_tpl;
15735 Roo.apply(this, depreciated_config);
15737 this.wrapEl = this.el.wrap().wrap();
15738 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15741 if(typeof(this.tpl) == "string"){
15742 this.tpl = new Roo.Template(this.tpl);
15744 // support xtype ctors..
15745 this.tpl = new Roo.factory(this.tpl, Roo);
15749 this.tpl.compile();
15754 * @event beforeclick
15755 * Fires before a click is processed. Returns false to cancel the default action.
15756 * @param {Roo.View} this
15757 * @param {Number} index The index of the target node
15758 * @param {HTMLElement} node The target node
15759 * @param {Roo.EventObject} e The raw event object
15761 "beforeclick" : true,
15764 * Fires when a template node is clicked.
15765 * @param {Roo.View} this
15766 * @param {Number} index The index of the target node
15767 * @param {HTMLElement} node The target node
15768 * @param {Roo.EventObject} e The raw event object
15773 * Fires when a template node is double clicked.
15774 * @param {Roo.View} this
15775 * @param {Number} index The index of the target node
15776 * @param {HTMLElement} node The target node
15777 * @param {Roo.EventObject} e The raw event object
15781 * @event contextmenu
15782 * Fires when a template node is right clicked.
15783 * @param {Roo.View} this
15784 * @param {Number} index The index of the target node
15785 * @param {HTMLElement} node The target node
15786 * @param {Roo.EventObject} e The raw event object
15788 "contextmenu" : true,
15790 * @event selectionchange
15791 * Fires when the selected nodes change.
15792 * @param {Roo.View} this
15793 * @param {Array} selections Array of the selected nodes
15795 "selectionchange" : true,
15798 * @event beforeselect
15799 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15800 * @param {Roo.View} this
15801 * @param {HTMLElement} node The node to be selected
15802 * @param {Array} selections Array of currently selected nodes
15804 "beforeselect" : true,
15806 * @event preparedata
15807 * Fires on every row to render, to allow you to change the data.
15808 * @param {Roo.View} this
15809 * @param {Object} data to be rendered (change this)
15811 "preparedata" : true
15819 "click": this.onClick,
15820 "dblclick": this.onDblClick,
15821 "contextmenu": this.onContextMenu,
15825 this.selections = [];
15827 this.cmp = new Roo.CompositeElementLite([]);
15829 this.store = Roo.factory(this.store, Roo.data);
15830 this.setStore(this.store, true);
15833 if ( this.footer && this.footer.xtype) {
15835 var fctr = this.wrapEl.appendChild(document.createElement("div"));
15837 this.footer.dataSource = this.store;
15838 this.footer.container = fctr;
15839 this.footer = Roo.factory(this.footer, Roo);
15840 fctr.insertFirst(this.el);
15842 // this is a bit insane - as the paging toolbar seems to detach the el..
15843 // dom.parentNode.parentNode.parentNode
15844 // they get detached?
15848 Roo.View.superclass.constructor.call(this);
15853 Roo.extend(Roo.View, Roo.util.Observable, {
15856 * @cfg {Roo.data.Store} store Data store to load data from.
15861 * @cfg {String|Roo.Element} el The container element.
15866 * @cfg {String|Roo.Template} tpl The template used by this View
15870 * @cfg {String} dataName the named area of the template to use as the data area
15871 * Works with domtemplates roo-name="name"
15875 * @cfg {String} selectedClass The css class to add to selected nodes
15877 selectedClass : "x-view-selected",
15879 * @cfg {String} emptyText The empty text to show when nothing is loaded.
15884 * @cfg {String} text to display on mask (default Loading)
15888 * @cfg {Boolean} multiSelect Allow multiple selection
15890 multiSelect : false,
15892 * @cfg {Boolean} singleSelect Allow single selection
15894 singleSelect: false,
15897 * @cfg {Boolean} toggleSelect - selecting
15899 toggleSelect : false,
15902 * @cfg {Boolean} tickable - selecting
15907 * Returns the element this view is bound to.
15908 * @return {Roo.Element}
15910 getEl : function(){
15911 return this.wrapEl;
15917 * Refreshes the view. - called by datachanged on the store. - do not call directly.
15919 refresh : function(){
15920 //Roo.log('refresh');
15923 // if we are using something like 'domtemplate', then
15924 // the what gets used is:
15925 // t.applySubtemplate(NAME, data, wrapping data..)
15926 // the outer template then get' applied with
15927 // the store 'extra data'
15928 // and the body get's added to the
15929 // roo-name="data" node?
15930 // <span class='roo-tpl-{name}'></span> ?????
15934 this.clearSelections();
15935 this.el.update("");
15937 var records = this.store.getRange();
15938 if(records.length < 1) {
15940 // is this valid?? = should it render a template??
15942 this.el.update(this.emptyText);
15946 if (this.dataName) {
15947 this.el.update(t.apply(this.store.meta)); //????
15948 el = this.el.child('.roo-tpl-' + this.dataName);
15951 for(var i = 0, len = records.length; i < len; i++){
15952 var data = this.prepareData(records[i].data, i, records[i]);
15953 this.fireEvent("preparedata", this, data, i, records[i]);
15955 var d = Roo.apply({}, data);
15958 Roo.apply(d, {'roo-id' : Roo.id()});
15962 Roo.each(this.parent.item, function(item){
15963 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15966 Roo.apply(d, {'roo-data-checked' : 'checked'});
15970 html[html.length] = Roo.util.Format.trim(
15972 t.applySubtemplate(this.dataName, d, this.store.meta) :
15979 el.update(html.join(""));
15980 this.nodes = el.dom.childNodes;
15981 this.updateIndexes(0);
15986 * Function to override to reformat the data that is sent to
15987 * the template for each node.
15988 * DEPRICATED - use the preparedata event handler.
15989 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
15990 * a JSON object for an UpdateManager bound view).
15992 prepareData : function(data, index, record)
15994 this.fireEvent("preparedata", this, data, index, record);
15998 onUpdate : function(ds, record){
15999 // Roo.log('on update');
16000 this.clearSelections();
16001 var index = this.store.indexOf(record);
16002 var n = this.nodes[index];
16003 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16004 n.parentNode.removeChild(n);
16005 this.updateIndexes(index, index);
16011 onAdd : function(ds, records, index)
16013 //Roo.log(['on Add', ds, records, index] );
16014 this.clearSelections();
16015 if(this.nodes.length == 0){
16019 var n = this.nodes[index];
16020 for(var i = 0, len = records.length; i < len; i++){
16021 var d = this.prepareData(records[i].data, i, records[i]);
16023 this.tpl.insertBefore(n, d);
16026 this.tpl.append(this.el, d);
16029 this.updateIndexes(index);
16032 onRemove : function(ds, record, index){
16033 // Roo.log('onRemove');
16034 this.clearSelections();
16035 var el = this.dataName ?
16036 this.el.child('.roo-tpl-' + this.dataName) :
16039 el.dom.removeChild(this.nodes[index]);
16040 this.updateIndexes(index);
16044 * Refresh an individual node.
16045 * @param {Number} index
16047 refreshNode : function(index){
16048 this.onUpdate(this.store, this.store.getAt(index));
16051 updateIndexes : function(startIndex, endIndex){
16052 var ns = this.nodes;
16053 startIndex = startIndex || 0;
16054 endIndex = endIndex || ns.length - 1;
16055 for(var i = startIndex; i <= endIndex; i++){
16056 ns[i].nodeIndex = i;
16061 * Changes the data store this view uses and refresh the view.
16062 * @param {Store} store
16064 setStore : function(store, initial){
16065 if(!initial && this.store){
16066 this.store.un("datachanged", this.refresh);
16067 this.store.un("add", this.onAdd);
16068 this.store.un("remove", this.onRemove);
16069 this.store.un("update", this.onUpdate);
16070 this.store.un("clear", this.refresh);
16071 this.store.un("beforeload", this.onBeforeLoad);
16072 this.store.un("load", this.onLoad);
16073 this.store.un("loadexception", this.onLoad);
16077 store.on("datachanged", this.refresh, this);
16078 store.on("add", this.onAdd, this);
16079 store.on("remove", this.onRemove, this);
16080 store.on("update", this.onUpdate, this);
16081 store.on("clear", this.refresh, this);
16082 store.on("beforeload", this.onBeforeLoad, this);
16083 store.on("load", this.onLoad, this);
16084 store.on("loadexception", this.onLoad, this);
16092 * onbeforeLoad - masks the loading area.
16095 onBeforeLoad : function(store,opts)
16097 //Roo.log('onBeforeLoad');
16099 this.el.update("");
16101 this.el.mask(this.mask ? this.mask : "Loading" );
16103 onLoad : function ()
16110 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16111 * @param {HTMLElement} node
16112 * @return {HTMLElement} The template node
16114 findItemFromChild : function(node){
16115 var el = this.dataName ?
16116 this.el.child('.roo-tpl-' + this.dataName,true) :
16119 if(!node || node.parentNode == el){
16122 var p = node.parentNode;
16123 while(p && p != el){
16124 if(p.parentNode == el){
16133 onClick : function(e){
16134 var item = this.findItemFromChild(e.getTarget());
16136 var index = this.indexOf(item);
16137 if(this.onItemClick(item, index, e) !== false){
16138 this.fireEvent("click", this, index, item, e);
16141 this.clearSelections();
16146 onContextMenu : function(e){
16147 var item = this.findItemFromChild(e.getTarget());
16149 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16154 onDblClick : function(e){
16155 var item = this.findItemFromChild(e.getTarget());
16157 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16161 onItemClick : function(item, index, e)
16163 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16166 if (this.toggleSelect) {
16167 var m = this.isSelected(item) ? 'unselect' : 'select';
16170 _t[m](item, true, false);
16173 if(this.multiSelect || this.singleSelect){
16174 if(this.multiSelect && e.shiftKey && this.lastSelection){
16175 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16177 this.select(item, this.multiSelect && e.ctrlKey);
16178 this.lastSelection = item;
16181 if(!this.tickable){
16182 e.preventDefault();
16190 * Get the number of selected nodes.
16193 getSelectionCount : function(){
16194 return this.selections.length;
16198 * Get the currently selected nodes.
16199 * @return {Array} An array of HTMLElements
16201 getSelectedNodes : function(){
16202 return this.selections;
16206 * Get the indexes of the selected nodes.
16209 getSelectedIndexes : function(){
16210 var indexes = [], s = this.selections;
16211 for(var i = 0, len = s.length; i < len; i++){
16212 indexes.push(s[i].nodeIndex);
16218 * Clear all selections
16219 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16221 clearSelections : function(suppressEvent){
16222 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16223 this.cmp.elements = this.selections;
16224 this.cmp.removeClass(this.selectedClass);
16225 this.selections = [];
16226 if(!suppressEvent){
16227 this.fireEvent("selectionchange", this, this.selections);
16233 * Returns true if the passed node is selected
16234 * @param {HTMLElement/Number} node The node or node index
16235 * @return {Boolean}
16237 isSelected : function(node){
16238 var s = this.selections;
16242 node = this.getNode(node);
16243 return s.indexOf(node) !== -1;
16248 * @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
16249 * @param {Boolean} keepExisting (optional) true to keep existing selections
16250 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16252 select : function(nodeInfo, keepExisting, suppressEvent){
16253 if(nodeInfo instanceof Array){
16255 this.clearSelections(true);
16257 for(var i = 0, len = nodeInfo.length; i < len; i++){
16258 this.select(nodeInfo[i], true, true);
16262 var node = this.getNode(nodeInfo);
16263 if(!node || this.isSelected(node)){
16264 return; // already selected.
16267 this.clearSelections(true);
16270 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16271 Roo.fly(node).addClass(this.selectedClass);
16272 this.selections.push(node);
16273 if(!suppressEvent){
16274 this.fireEvent("selectionchange", this, this.selections);
16282 * @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
16283 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16284 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16286 unselect : function(nodeInfo, keepExisting, suppressEvent)
16288 if(nodeInfo instanceof Array){
16289 Roo.each(this.selections, function(s) {
16290 this.unselect(s, nodeInfo);
16294 var node = this.getNode(nodeInfo);
16295 if(!node || !this.isSelected(node)){
16296 //Roo.log("not selected");
16297 return; // not selected.
16301 Roo.each(this.selections, function(s) {
16303 Roo.fly(node).removeClass(this.selectedClass);
16310 this.selections= ns;
16311 this.fireEvent("selectionchange", this, this.selections);
16315 * Gets a template node.
16316 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16317 * @return {HTMLElement} The node or null if it wasn't found
16319 getNode : function(nodeInfo){
16320 if(typeof nodeInfo == "string"){
16321 return document.getElementById(nodeInfo);
16322 }else if(typeof nodeInfo == "number"){
16323 return this.nodes[nodeInfo];
16329 * Gets a range template nodes.
16330 * @param {Number} startIndex
16331 * @param {Number} endIndex
16332 * @return {Array} An array of nodes
16334 getNodes : function(start, end){
16335 var ns = this.nodes;
16336 start = start || 0;
16337 end = typeof end == "undefined" ? ns.length - 1 : end;
16340 for(var i = start; i <= end; i++){
16344 for(var i = start; i >= end; i--){
16352 * Finds the index of the passed node
16353 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16354 * @return {Number} The index of the node or -1
16356 indexOf : function(node){
16357 node = this.getNode(node);
16358 if(typeof node.nodeIndex == "number"){
16359 return node.nodeIndex;
16361 var ns = this.nodes;
16362 for(var i = 0, len = ns.length; i < len; i++){
16373 * based on jquery fullcalendar
16377 Roo.bootstrap = Roo.bootstrap || {};
16379 * @class Roo.bootstrap.Calendar
16380 * @extends Roo.bootstrap.Component
16381 * Bootstrap Calendar class
16382 * @cfg {Boolean} loadMask (true|false) default false
16383 * @cfg {Object} header generate the user specific header of the calendar, default false
16386 * Create a new Container
16387 * @param {Object} config The config object
16392 Roo.bootstrap.Calendar = function(config){
16393 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16397 * Fires when a date is selected
16398 * @param {DatePicker} this
16399 * @param {Date} date The selected date
16403 * @event monthchange
16404 * Fires when the displayed month changes
16405 * @param {DatePicker} this
16406 * @param {Date} date The selected month
16408 'monthchange': true,
16410 * @event evententer
16411 * Fires when mouse over an event
16412 * @param {Calendar} this
16413 * @param {event} Event
16415 'evententer': true,
16417 * @event eventleave
16418 * Fires when the mouse leaves an
16419 * @param {Calendar} this
16422 'eventleave': true,
16424 * @event eventclick
16425 * Fires when the mouse click an
16426 * @param {Calendar} this
16435 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16438 * @cfg {Number} startDay
16439 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16447 getAutoCreate : function(){
16450 var fc_button = function(name, corner, style, content ) {
16451 return Roo.apply({},{
16453 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16455 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16458 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16469 style : 'width:100%',
16476 cls : 'fc-header-left',
16478 fc_button('prev', 'left', 'arrow', '‹' ),
16479 fc_button('next', 'right', 'arrow', '›' ),
16480 { tag: 'span', cls: 'fc-header-space' },
16481 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16489 cls : 'fc-header-center',
16493 cls: 'fc-header-title',
16496 html : 'month / year'
16504 cls : 'fc-header-right',
16506 /* fc_button('month', 'left', '', 'month' ),
16507 fc_button('week', '', '', 'week' ),
16508 fc_button('day', 'right', '', 'day' )
16520 header = this.header;
16523 var cal_heads = function() {
16525 // fixme - handle this.
16527 for (var i =0; i < Date.dayNames.length; i++) {
16528 var d = Date.dayNames[i];
16531 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16532 html : d.substring(0,3)
16536 ret[0].cls += ' fc-first';
16537 ret[6].cls += ' fc-last';
16540 var cal_cell = function(n) {
16543 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16548 cls: 'fc-day-number',
16552 cls: 'fc-day-content',
16556 style: 'position: relative;' // height: 17px;
16568 var cal_rows = function() {
16571 for (var r = 0; r < 6; r++) {
16578 for (var i =0; i < Date.dayNames.length; i++) {
16579 var d = Date.dayNames[i];
16580 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16583 row.cn[0].cls+=' fc-first';
16584 row.cn[0].cn[0].style = 'min-height:90px';
16585 row.cn[6].cls+=' fc-last';
16589 ret[0].cls += ' fc-first';
16590 ret[4].cls += ' fc-prev-last';
16591 ret[5].cls += ' fc-last';
16598 cls: 'fc-border-separate',
16599 style : 'width:100%',
16607 cls : 'fc-first fc-last',
16625 cls : 'fc-content',
16626 style : "position: relative;",
16629 cls : 'fc-view fc-view-month fc-grid',
16630 style : 'position: relative',
16631 unselectable : 'on',
16634 cls : 'fc-event-container',
16635 style : 'position:absolute;z-index:8;top:0;left:0;'
16653 initEvents : function()
16656 throw "can not find store for calendar";
16662 style: "text-align:center",
16666 style: "background-color:white;width:50%;margin:250 auto",
16670 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16681 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16683 var size = this.el.select('.fc-content', true).first().getSize();
16684 this.maskEl.setSize(size.width, size.height);
16685 this.maskEl.enableDisplayMode("block");
16686 if(!this.loadMask){
16687 this.maskEl.hide();
16690 this.store = Roo.factory(this.store, Roo.data);
16691 this.store.on('load', this.onLoad, this);
16692 this.store.on('beforeload', this.onBeforeLoad, this);
16696 this.cells = this.el.select('.fc-day',true);
16697 //Roo.log(this.cells);
16698 this.textNodes = this.el.query('.fc-day-number');
16699 this.cells.addClassOnOver('fc-state-hover');
16701 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16702 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16703 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16704 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16706 this.on('monthchange', this.onMonthChange, this);
16708 this.update(new Date().clearTime());
16711 resize : function() {
16712 var sz = this.el.getSize();
16714 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16715 this.el.select('.fc-day-content div',true).setHeight(34);
16720 showPrevMonth : function(e){
16721 this.update(this.activeDate.add("mo", -1));
16723 showToday : function(e){
16724 this.update(new Date().clearTime());
16727 showNextMonth : function(e){
16728 this.update(this.activeDate.add("mo", 1));
16732 showPrevYear : function(){
16733 this.update(this.activeDate.add("y", -1));
16737 showNextYear : function(){
16738 this.update(this.activeDate.add("y", 1));
16743 update : function(date)
16745 var vd = this.activeDate;
16746 this.activeDate = date;
16747 // if(vd && this.el){
16748 // var t = date.getTime();
16749 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16750 // Roo.log('using add remove');
16752 // this.fireEvent('monthchange', this, date);
16754 // this.cells.removeClass("fc-state-highlight");
16755 // this.cells.each(function(c){
16756 // if(c.dateValue == t){
16757 // c.addClass("fc-state-highlight");
16758 // setTimeout(function(){
16759 // try{c.dom.firstChild.focus();}catch(e){}
16769 var days = date.getDaysInMonth();
16771 var firstOfMonth = date.getFirstDateOfMonth();
16772 var startingPos = firstOfMonth.getDay()-this.startDay;
16774 if(startingPos < this.startDay){
16778 var pm = date.add(Date.MONTH, -1);
16779 var prevStart = pm.getDaysInMonth()-startingPos;
16781 this.cells = this.el.select('.fc-day',true);
16782 this.textNodes = this.el.query('.fc-day-number');
16783 this.cells.addClassOnOver('fc-state-hover');
16785 var cells = this.cells.elements;
16786 var textEls = this.textNodes;
16788 Roo.each(cells, function(cell){
16789 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16792 days += startingPos;
16794 // convert everything to numbers so it's fast
16795 var day = 86400000;
16796 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16799 //Roo.log(prevStart);
16801 var today = new Date().clearTime().getTime();
16802 var sel = date.clearTime().getTime();
16803 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16804 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16805 var ddMatch = this.disabledDatesRE;
16806 var ddText = this.disabledDatesText;
16807 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16808 var ddaysText = this.disabledDaysText;
16809 var format = this.format;
16811 var setCellClass = function(cal, cell){
16815 //Roo.log('set Cell Class');
16817 var t = d.getTime();
16821 cell.dateValue = t;
16823 cell.className += " fc-today";
16824 cell.className += " fc-state-highlight";
16825 cell.title = cal.todayText;
16828 // disable highlight in other month..
16829 //cell.className += " fc-state-highlight";
16834 cell.className = " fc-state-disabled";
16835 cell.title = cal.minText;
16839 cell.className = " fc-state-disabled";
16840 cell.title = cal.maxText;
16844 if(ddays.indexOf(d.getDay()) != -1){
16845 cell.title = ddaysText;
16846 cell.className = " fc-state-disabled";
16849 if(ddMatch && format){
16850 var fvalue = d.dateFormat(format);
16851 if(ddMatch.test(fvalue)){
16852 cell.title = ddText.replace("%0", fvalue);
16853 cell.className = " fc-state-disabled";
16857 if (!cell.initialClassName) {
16858 cell.initialClassName = cell.dom.className;
16861 cell.dom.className = cell.initialClassName + ' ' + cell.className;
16866 for(; i < startingPos; i++) {
16867 textEls[i].innerHTML = (++prevStart);
16868 d.setDate(d.getDate()+1);
16870 cells[i].className = "fc-past fc-other-month";
16871 setCellClass(this, cells[i]);
16876 for(; i < days; i++){
16877 intDay = i - startingPos + 1;
16878 textEls[i].innerHTML = (intDay);
16879 d.setDate(d.getDate()+1);
16881 cells[i].className = ''; // "x-date-active";
16882 setCellClass(this, cells[i]);
16886 for(; i < 42; i++) {
16887 textEls[i].innerHTML = (++extraDays);
16888 d.setDate(d.getDate()+1);
16890 cells[i].className = "fc-future fc-other-month";
16891 setCellClass(this, cells[i]);
16894 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16896 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16898 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16899 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16901 if(totalRows != 6){
16902 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16903 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16906 this.fireEvent('monthchange', this, date);
16910 if(!this.internalRender){
16911 var main = this.el.dom.firstChild;
16912 var w = main.offsetWidth;
16913 this.el.setWidth(w + this.el.getBorderWidth("lr"));
16914 Roo.fly(main).setWidth(w);
16915 this.internalRender = true;
16916 // opera does not respect the auto grow header center column
16917 // then, after it gets a width opera refuses to recalculate
16918 // without a second pass
16919 if(Roo.isOpera && !this.secondPass){
16920 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16921 this.secondPass = true;
16922 this.update.defer(10, this, [date]);
16929 findCell : function(dt) {
16930 dt = dt.clearTime().getTime();
16932 this.cells.each(function(c){
16933 //Roo.log("check " +c.dateValue + '?=' + dt);
16934 if(c.dateValue == dt){
16944 findCells : function(ev) {
16945 var s = ev.start.clone().clearTime().getTime();
16947 var e= ev.end.clone().clearTime().getTime();
16950 this.cells.each(function(c){
16951 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16953 if(c.dateValue > e){
16956 if(c.dateValue < s){
16965 // findBestRow: function(cells)
16969 // for (var i =0 ; i < cells.length;i++) {
16970 // ret = Math.max(cells[i].rows || 0,ret);
16977 addItem : function(ev)
16979 // look for vertical location slot in
16980 var cells = this.findCells(ev);
16982 // ev.row = this.findBestRow(cells);
16984 // work out the location.
16988 for(var i =0; i < cells.length; i++) {
16990 cells[i].row = cells[0].row;
16993 cells[i].row = cells[i].row + 1;
17003 if (crow.start.getY() == cells[i].getY()) {
17005 crow.end = cells[i];
17022 cells[0].events.push(ev);
17024 this.calevents.push(ev);
17027 clearEvents: function() {
17029 if(!this.calevents){
17033 Roo.each(this.cells.elements, function(c){
17039 Roo.each(this.calevents, function(e) {
17040 Roo.each(e.els, function(el) {
17041 el.un('mouseenter' ,this.onEventEnter, this);
17042 el.un('mouseleave' ,this.onEventLeave, this);
17047 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17053 renderEvents: function()
17057 this.cells.each(function(c) {
17066 if(c.row != c.events.length){
17067 r = 4 - (4 - (c.row - c.events.length));
17070 c.events = ev.slice(0, r);
17071 c.more = ev.slice(r);
17073 if(c.more.length && c.more.length == 1){
17074 c.events.push(c.more.pop());
17077 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17081 this.cells.each(function(c) {
17083 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17086 for (var e = 0; e < c.events.length; e++){
17087 var ev = c.events[e];
17088 var rows = ev.rows;
17090 for(var i = 0; i < rows.length; i++) {
17092 // how many rows should it span..
17095 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17096 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17098 unselectable : "on",
17101 cls: 'fc-event-inner',
17105 // cls: 'fc-event-time',
17106 // html : cells.length > 1 ? '' : ev.time
17110 cls: 'fc-event-title',
17111 html : String.format('{0}', ev.title)
17118 cls: 'ui-resizable-handle ui-resizable-e',
17119 html : '  '
17126 cfg.cls += ' fc-event-start';
17128 if ((i+1) == rows.length) {
17129 cfg.cls += ' fc-event-end';
17132 var ctr = _this.el.select('.fc-event-container',true).first();
17133 var cg = ctr.createChild(cfg);
17135 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17136 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17138 var r = (c.more.length) ? 1 : 0;
17139 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17140 cg.setWidth(ebox.right - sbox.x -2);
17142 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17143 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17144 cg.on('click', _this.onEventClick, _this, ev);
17155 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17156 style : 'position: absolute',
17157 unselectable : "on",
17160 cls: 'fc-event-inner',
17164 cls: 'fc-event-title',
17172 cls: 'ui-resizable-handle ui-resizable-e',
17173 html : '  '
17179 var ctr = _this.el.select('.fc-event-container',true).first();
17180 var cg = ctr.createChild(cfg);
17182 var sbox = c.select('.fc-day-content',true).first().getBox();
17183 var ebox = c.select('.fc-day-content',true).first().getBox();
17185 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17186 cg.setWidth(ebox.right - sbox.x -2);
17188 cg.on('click', _this.onMoreEventClick, _this, c.more);
17198 onEventEnter: function (e, el,event,d) {
17199 this.fireEvent('evententer', this, el, event);
17202 onEventLeave: function (e, el,event,d) {
17203 this.fireEvent('eventleave', this, el, event);
17206 onEventClick: function (e, el,event,d) {
17207 this.fireEvent('eventclick', this, el, event);
17210 onMonthChange: function () {
17214 onMoreEventClick: function(e, el, more)
17218 this.calpopover.placement = 'right';
17219 this.calpopover.setTitle('More');
17221 this.calpopover.setContent('');
17223 var ctr = this.calpopover.el.select('.popover-content', true).first();
17225 Roo.each(more, function(m){
17227 cls : 'fc-event-hori fc-event-draggable',
17230 var cg = ctr.createChild(cfg);
17232 cg.on('click', _this.onEventClick, _this, m);
17235 this.calpopover.show(el);
17240 onLoad: function ()
17242 this.calevents = [];
17245 if(this.store.getCount() > 0){
17246 this.store.data.each(function(d){
17249 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17250 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17251 time : d.data.start_time,
17252 title : d.data.title,
17253 description : d.data.description,
17254 venue : d.data.venue
17259 this.renderEvents();
17261 if(this.calevents.length && this.loadMask){
17262 this.maskEl.hide();
17266 onBeforeLoad: function()
17268 this.clearEvents();
17270 this.maskEl.show();
17284 * @class Roo.bootstrap.Popover
17285 * @extends Roo.bootstrap.Component
17286 * Bootstrap Popover class
17287 * @cfg {String} html contents of the popover (or false to use children..)
17288 * @cfg {String} title of popover (or false to hide)
17289 * @cfg {String} placement how it is placed
17290 * @cfg {String} trigger click || hover (or false to trigger manually)
17291 * @cfg {String} over what (parent or false to trigger manually.)
17292 * @cfg {Number} delay - delay before showing
17295 * Create a new Popover
17296 * @param {Object} config The config object
17299 Roo.bootstrap.Popover = function(config){
17300 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17306 * After the popover show
17308 * @param {Roo.bootstrap.Popover} this
17313 * After the popover hide
17315 * @param {Roo.bootstrap.Popover} this
17321 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17323 title: 'Fill in a title',
17326 placement : 'right',
17327 trigger : 'hover', // hover
17333 can_build_overlaid : false,
17335 getChildContainer : function()
17337 return this.el.select('.popover-content',true).first();
17340 getAutoCreate : function(){
17343 cls : 'popover roo-dynamic',
17344 style: 'display:block',
17350 cls : 'popover-inner',
17354 cls: 'popover-title',
17358 cls : 'popover-content',
17369 setTitle: function(str)
17372 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17374 setContent: function(str)
17377 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17379 // as it get's added to the bottom of the page.
17380 onRender : function(ct, position)
17382 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17384 var cfg = Roo.apply({}, this.getAutoCreate());
17388 cfg.cls += ' ' + this.cls;
17391 cfg.style = this.style;
17393 //Roo.log("adding to ");
17394 this.el = Roo.get(document.body).createChild(cfg, position);
17395 // Roo.log(this.el);
17400 initEvents : function()
17402 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17403 this.el.enableDisplayMode('block');
17405 if (this.over === false) {
17408 if (this.triggers === false) {
17411 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17412 var triggers = this.trigger ? this.trigger.split(' ') : [];
17413 Roo.each(triggers, function(trigger) {
17415 if (trigger == 'click') {
17416 on_el.on('click', this.toggle, this);
17417 } else if (trigger != 'manual') {
17418 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17419 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17421 on_el.on(eventIn ,this.enter, this);
17422 on_el.on(eventOut, this.leave, this);
17433 toggle : function () {
17434 this.hoverState == 'in' ? this.leave() : this.enter();
17437 enter : function () {
17439 clearTimeout(this.timeout);
17441 this.hoverState = 'in';
17443 if (!this.delay || !this.delay.show) {
17448 this.timeout = setTimeout(function () {
17449 if (_t.hoverState == 'in') {
17452 }, this.delay.show)
17455 leave : function() {
17456 clearTimeout(this.timeout);
17458 this.hoverState = 'out';
17460 if (!this.delay || !this.delay.hide) {
17465 this.timeout = setTimeout(function () {
17466 if (_t.hoverState == 'out') {
17469 }, this.delay.hide)
17472 show : function (on_el)
17475 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17479 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17480 if (this.html !== false) {
17481 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17483 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17484 if (!this.title.length) {
17485 this.el.select('.popover-title',true).hide();
17488 var placement = typeof this.placement == 'function' ?
17489 this.placement.call(this, this.el, on_el) :
17492 var autoToken = /\s?auto?\s?/i;
17493 var autoPlace = autoToken.test(placement);
17495 placement = placement.replace(autoToken, '') || 'top';
17499 //this.el.setXY([0,0]);
17501 this.el.dom.style.display='block';
17502 this.el.addClass(placement);
17504 //this.el.appendTo(on_el);
17506 var p = this.getPosition();
17507 var box = this.el.getBox();
17512 var align = Roo.bootstrap.Popover.alignment[placement];
17515 this.el.alignTo(on_el, align[0],align[1]);
17516 //var arrow = this.el.select('.arrow',true).first();
17517 //arrow.set(align[2],
17519 this.el.addClass('in');
17522 if (this.el.hasClass('fade')) {
17526 this.hoverState = 'in';
17528 this.fireEvent('show', this);
17533 this.el.setXY([0,0]);
17534 this.el.removeClass('in');
17536 this.hoverState = null;
17538 this.fireEvent('hide', this);
17543 Roo.bootstrap.Popover.alignment = {
17544 'left' : ['r-l', [-10,0], 'right'],
17545 'right' : ['l-r', [10,0], 'left'],
17546 'bottom' : ['t-b', [0,10], 'top'],
17547 'top' : [ 'b-t', [0,-10], 'bottom']
17558 * @class Roo.bootstrap.Progress
17559 * @extends Roo.bootstrap.Component
17560 * Bootstrap Progress class
17561 * @cfg {Boolean} striped striped of the progress bar
17562 * @cfg {Boolean} active animated of the progress bar
17566 * Create a new Progress
17567 * @param {Object} config The config object
17570 Roo.bootstrap.Progress = function(config){
17571 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17574 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17579 getAutoCreate : function(){
17587 cfg.cls += ' progress-striped';
17591 cfg.cls += ' active';
17610 * @class Roo.bootstrap.ProgressBar
17611 * @extends Roo.bootstrap.Component
17612 * Bootstrap ProgressBar class
17613 * @cfg {Number} aria_valuenow aria-value now
17614 * @cfg {Number} aria_valuemin aria-value min
17615 * @cfg {Number} aria_valuemax aria-value max
17616 * @cfg {String} label label for the progress bar
17617 * @cfg {String} panel (success | info | warning | danger )
17618 * @cfg {String} role role of the progress bar
17619 * @cfg {String} sr_only text
17623 * Create a new ProgressBar
17624 * @param {Object} config The config object
17627 Roo.bootstrap.ProgressBar = function(config){
17628 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17631 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17635 aria_valuemax : 100,
17641 getAutoCreate : function()
17646 cls: 'progress-bar',
17647 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17659 cfg.role = this.role;
17662 if(this.aria_valuenow){
17663 cfg['aria-valuenow'] = this.aria_valuenow;
17666 if(this.aria_valuemin){
17667 cfg['aria-valuemin'] = this.aria_valuemin;
17670 if(this.aria_valuemax){
17671 cfg['aria-valuemax'] = this.aria_valuemax;
17674 if(this.label && !this.sr_only){
17675 cfg.html = this.label;
17679 cfg.cls += ' progress-bar-' + this.panel;
17685 update : function(aria_valuenow)
17687 this.aria_valuenow = aria_valuenow;
17689 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17704 * @class Roo.bootstrap.TabGroup
17705 * @extends Roo.bootstrap.Column
17706 * Bootstrap Column class
17707 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17708 * @cfg {Boolean} carousel true to make the group behave like a carousel
17709 * @cfg {Boolean} bullets show bullets for the panels
17710 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17711 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17712 * @cfg {Boolean} showarrow (true|false) show arrow default true
17715 * Create a new TabGroup
17716 * @param {Object} config The config object
17719 Roo.bootstrap.TabGroup = function(config){
17720 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17722 this.navId = Roo.id();
17725 Roo.bootstrap.TabGroup.register(this);
17729 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
17732 transition : false,
17737 slideOnTouch : false,
17740 getAutoCreate : function()
17742 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17744 cfg.cls += ' tab-content';
17746 if (this.carousel) {
17747 cfg.cls += ' carousel slide';
17750 cls : 'carousel-inner',
17754 if(this.bullets && !Roo.isTouch){
17757 cls : 'carousel-bullets',
17761 if(this.bullets_cls){
17762 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17769 cfg.cn[0].cn.push(bullets);
17772 if(this.showarrow){
17773 cfg.cn[0].cn.push({
17775 class : 'carousel-arrow',
17779 class : 'carousel-prev',
17783 class : 'fa fa-chevron-left'
17789 class : 'carousel-next',
17793 class : 'fa fa-chevron-right'
17806 initEvents: function()
17808 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17809 // this.el.on("touchstart", this.onTouchStart, this);
17812 if(this.autoslide){
17815 this.slideFn = window.setInterval(function() {
17816 _this.showPanelNext();
17820 if(this.showarrow){
17821 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17822 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17828 // onTouchStart : function(e, el, o)
17830 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17834 // this.showPanelNext();
17838 getChildContainer : function()
17840 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17844 * register a Navigation item
17845 * @param {Roo.bootstrap.NavItem} the navitem to add
17847 register : function(item)
17849 this.tabs.push( item);
17850 item.navId = this.navId; // not really needed..
17855 getActivePanel : function()
17858 Roo.each(this.tabs, function(t) {
17868 getPanelByName : function(n)
17871 Roo.each(this.tabs, function(t) {
17872 if (t.tabId == n) {
17880 indexOfPanel : function(p)
17883 Roo.each(this.tabs, function(t,i) {
17884 if (t.tabId == p.tabId) {
17893 * show a specific panel
17894 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17895 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17897 showPanel : function (pan)
17899 if(this.transition || typeof(pan) == 'undefined'){
17900 Roo.log("waiting for the transitionend");
17904 if (typeof(pan) == 'number') {
17905 pan = this.tabs[pan];
17908 if (typeof(pan) == 'string') {
17909 pan = this.getPanelByName(pan);
17912 var cur = this.getActivePanel();
17915 Roo.log('pan or acitve pan is undefined');
17919 if (pan.tabId == this.getActivePanel().tabId) {
17923 if (false === cur.fireEvent('beforedeactivate')) {
17927 if(this.bullets > 0 && !Roo.isTouch){
17928 this.setActiveBullet(this.indexOfPanel(pan));
17931 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17933 this.transition = true;
17934 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
17935 var lr = dir == 'next' ? 'left' : 'right';
17936 pan.el.addClass(dir); // or prev
17937 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17938 cur.el.addClass(lr); // or right
17939 pan.el.addClass(lr);
17942 cur.el.on('transitionend', function() {
17943 Roo.log("trans end?");
17945 pan.el.removeClass([lr,dir]);
17946 pan.setActive(true);
17948 cur.el.removeClass([lr]);
17949 cur.setActive(false);
17951 _this.transition = false;
17953 }, this, { single: true } );
17958 cur.setActive(false);
17959 pan.setActive(true);
17964 showPanelNext : function()
17966 var i = this.indexOfPanel(this.getActivePanel());
17968 if (i >= this.tabs.length - 1 && !this.autoslide) {
17972 if (i >= this.tabs.length - 1 && this.autoslide) {
17976 this.showPanel(this.tabs[i+1]);
17979 showPanelPrev : function()
17981 var i = this.indexOfPanel(this.getActivePanel());
17983 if (i < 1 && !this.autoslide) {
17987 if (i < 1 && this.autoslide) {
17988 i = this.tabs.length;
17991 this.showPanel(this.tabs[i-1]);
17995 addBullet: function()
17997 if(!this.bullets || Roo.isTouch){
18000 var ctr = this.el.select('.carousel-bullets',true).first();
18001 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18002 var bullet = ctr.createChild({
18003 cls : 'bullet bullet-' + i
18004 },ctr.dom.lastChild);
18009 bullet.on('click', (function(e, el, o, ii, t){
18011 e.preventDefault();
18013 this.showPanel(ii);
18015 if(this.autoslide && this.slideFn){
18016 clearInterval(this.slideFn);
18017 this.slideFn = window.setInterval(function() {
18018 _this.showPanelNext();
18022 }).createDelegate(this, [i, bullet], true));
18027 setActiveBullet : function(i)
18033 Roo.each(this.el.select('.bullet', true).elements, function(el){
18034 el.removeClass('selected');
18037 var bullet = this.el.select('.bullet-' + i, true).first();
18043 bullet.addClass('selected');
18054 Roo.apply(Roo.bootstrap.TabGroup, {
18058 * register a Navigation Group
18059 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18061 register : function(navgrp)
18063 this.groups[navgrp.navId] = navgrp;
18067 * fetch a Navigation Group based on the navigation ID
18068 * if one does not exist , it will get created.
18069 * @param {string} the navgroup to add
18070 * @returns {Roo.bootstrap.NavGroup} the navgroup
18072 get: function(navId) {
18073 if (typeof(this.groups[navId]) == 'undefined') {
18074 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18076 return this.groups[navId] ;
18091 * @class Roo.bootstrap.TabPanel
18092 * @extends Roo.bootstrap.Component
18093 * Bootstrap TabPanel class
18094 * @cfg {Boolean} active panel active
18095 * @cfg {String} html panel content
18096 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18097 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18098 * @cfg {String} href click to link..
18102 * Create a new TabPanel
18103 * @param {Object} config The config object
18106 Roo.bootstrap.TabPanel = function(config){
18107 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18111 * Fires when the active status changes
18112 * @param {Roo.bootstrap.TabPanel} this
18113 * @param {Boolean} state the new state
18118 * @event beforedeactivate
18119 * Fires before a tab is de-activated - can be used to do validation on a form.
18120 * @param {Roo.bootstrap.TabPanel} this
18121 * @return {Boolean} false if there is an error
18124 'beforedeactivate': true
18127 this.tabId = this.tabId || Roo.id();
18131 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18139 getAutoCreate : function(){
18142 // item is needed for carousel - not sure if it has any effect otherwise
18143 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18144 html: this.html || ''
18148 cfg.cls += ' active';
18152 cfg.tabId = this.tabId;
18159 initEvents: function()
18161 var p = this.parent();
18163 this.navId = this.navId || p.navId;
18165 if (typeof(this.navId) != 'undefined') {
18166 // not really needed.. but just in case.. parent should be a NavGroup.
18167 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18171 var i = tg.tabs.length - 1;
18173 if(this.active && tg.bullets > 0 && i < tg.bullets){
18174 tg.setActiveBullet(i);
18178 this.el.on('click', this.onClick, this);
18181 this.el.on("touchstart", this.onTouchStart, this);
18182 this.el.on("touchmove", this.onTouchMove, this);
18183 this.el.on("touchend", this.onTouchEnd, this);
18188 onRender : function(ct, position)
18190 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18193 setActive : function(state)
18195 Roo.log("panel - set active " + this.tabId + "=" + state);
18197 this.active = state;
18199 this.el.removeClass('active');
18201 } else if (!this.el.hasClass('active')) {
18202 this.el.addClass('active');
18205 this.fireEvent('changed', this, state);
18208 onClick : function(e)
18210 e.preventDefault();
18212 if(!this.href.length){
18216 window.location.href = this.href;
18225 onTouchStart : function(e)
18227 this.swiping = false;
18229 this.startX = e.browserEvent.touches[0].clientX;
18230 this.startY = e.browserEvent.touches[0].clientY;
18233 onTouchMove : function(e)
18235 this.swiping = true;
18237 this.endX = e.browserEvent.touches[0].clientX;
18238 this.endY = e.browserEvent.touches[0].clientY;
18241 onTouchEnd : function(e)
18248 var tabGroup = this.parent();
18250 if(this.endX > this.startX){ // swiping right
18251 tabGroup.showPanelPrev();
18255 if(this.startX > this.endX){ // swiping left
18256 tabGroup.showPanelNext();
18275 * @class Roo.bootstrap.DateField
18276 * @extends Roo.bootstrap.Input
18277 * Bootstrap DateField class
18278 * @cfg {Number} weekStart default 0
18279 * @cfg {String} viewMode default empty, (months|years)
18280 * @cfg {String} minViewMode default empty, (months|years)
18281 * @cfg {Number} startDate default -Infinity
18282 * @cfg {Number} endDate default Infinity
18283 * @cfg {Boolean} todayHighlight default false
18284 * @cfg {Boolean} todayBtn default false
18285 * @cfg {Boolean} calendarWeeks default false
18286 * @cfg {Object} daysOfWeekDisabled default empty
18287 * @cfg {Boolean} singleMode default false (true | false)
18289 * @cfg {Boolean} keyboardNavigation default true
18290 * @cfg {String} language default en
18293 * Create a new DateField
18294 * @param {Object} config The config object
18297 Roo.bootstrap.DateField = function(config){
18298 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18302 * Fires when this field show.
18303 * @param {Roo.bootstrap.DateField} this
18304 * @param {Mixed} date The date value
18309 * Fires when this field hide.
18310 * @param {Roo.bootstrap.DateField} this
18311 * @param {Mixed} date The date value
18316 * Fires when select a date.
18317 * @param {Roo.bootstrap.DateField} this
18318 * @param {Mixed} date The date value
18322 * @event beforeselect
18323 * Fires when before select a date.
18324 * @param {Roo.bootstrap.DateField} this
18325 * @param {Mixed} date The date value
18327 beforeselect : true
18331 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18334 * @cfg {String} format
18335 * The default date format string which can be overriden for localization support. The format must be
18336 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18340 * @cfg {String} altFormats
18341 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18342 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18344 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18352 todayHighlight : false,
18358 keyboardNavigation: true,
18360 calendarWeeks: false,
18362 startDate: -Infinity,
18366 daysOfWeekDisabled: [],
18370 singleMode : false,
18372 UTCDate: function()
18374 return new Date(Date.UTC.apply(Date, arguments));
18377 UTCToday: function()
18379 var today = new Date();
18380 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18383 getDate: function() {
18384 var d = this.getUTCDate();
18385 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18388 getUTCDate: function() {
18392 setDate: function(d) {
18393 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18396 setUTCDate: function(d) {
18398 this.setValue(this.formatDate(this.date));
18401 onRender: function(ct, position)
18404 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18406 this.language = this.language || 'en';
18407 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18408 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18410 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18411 this.format = this.format || 'm/d/y';
18412 this.isInline = false;
18413 this.isInput = true;
18414 this.component = this.el.select('.add-on', true).first() || false;
18415 this.component = (this.component && this.component.length === 0) ? false : this.component;
18416 this.hasInput = this.component && this.inputEl().length;
18418 if (typeof(this.minViewMode === 'string')) {
18419 switch (this.minViewMode) {
18421 this.minViewMode = 1;
18424 this.minViewMode = 2;
18427 this.minViewMode = 0;
18432 if (typeof(this.viewMode === 'string')) {
18433 switch (this.viewMode) {
18446 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18448 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18450 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18452 this.picker().on('mousedown', this.onMousedown, this);
18453 this.picker().on('click', this.onClick, this);
18455 this.picker().addClass('datepicker-dropdown');
18457 this.startViewMode = this.viewMode;
18459 if(this.singleMode){
18460 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18461 v.setVisibilityMode(Roo.Element.DISPLAY);
18465 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18466 v.setStyle('width', '189px');
18470 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18471 if(!this.calendarWeeks){
18476 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18477 v.attr('colspan', function(i, val){
18478 return parseInt(val) + 1;
18483 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18485 this.setStartDate(this.startDate);
18486 this.setEndDate(this.endDate);
18488 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18495 if(this.isInline) {
18500 picker : function()
18502 return this.pickerEl;
18503 // return this.el.select('.datepicker', true).first();
18506 fillDow: function()
18508 var dowCnt = this.weekStart;
18517 if(this.calendarWeeks){
18525 while (dowCnt < this.weekStart + 7) {
18529 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18533 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18536 fillMonths: function()
18539 var months = this.picker().select('>.datepicker-months td', true).first();
18541 months.dom.innerHTML = '';
18547 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18550 months.createChild(month);
18557 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;
18559 if (this.date < this.startDate) {
18560 this.viewDate = new Date(this.startDate);
18561 } else if (this.date > this.endDate) {
18562 this.viewDate = new Date(this.endDate);
18564 this.viewDate = new Date(this.date);
18572 var d = new Date(this.viewDate),
18573 year = d.getUTCFullYear(),
18574 month = d.getUTCMonth(),
18575 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18576 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18577 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18578 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18579 currentDate = this.date && this.date.valueOf(),
18580 today = this.UTCToday();
18582 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18584 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18586 // this.picker.select('>tfoot th.today').
18587 // .text(dates[this.language].today)
18588 // .toggle(this.todayBtn !== false);
18590 this.updateNavArrows();
18593 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18595 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18597 prevMonth.setUTCDate(day);
18599 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18601 var nextMonth = new Date(prevMonth);
18603 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18605 nextMonth = nextMonth.valueOf();
18607 var fillMonths = false;
18609 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18611 while(prevMonth.valueOf() < nextMonth) {
18614 if (prevMonth.getUTCDay() === this.weekStart) {
18616 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18624 if(this.calendarWeeks){
18625 // ISO 8601: First week contains first thursday.
18626 // ISO also states week starts on Monday, but we can be more abstract here.
18628 // Start of current week: based on weekstart/current date
18629 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18630 // Thursday of this week
18631 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18632 // First Thursday of year, year from thursday
18633 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18634 // Calendar week: ms between thursdays, div ms per day, div 7 days
18635 calWeek = (th - yth) / 864e5 / 7 + 1;
18637 fillMonths.cn.push({
18645 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18647 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18650 if (this.todayHighlight &&
18651 prevMonth.getUTCFullYear() == today.getFullYear() &&
18652 prevMonth.getUTCMonth() == today.getMonth() &&
18653 prevMonth.getUTCDate() == today.getDate()) {
18654 clsName += ' today';
18657 if (currentDate && prevMonth.valueOf() === currentDate) {
18658 clsName += ' active';
18661 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18662 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18663 clsName += ' disabled';
18666 fillMonths.cn.push({
18668 cls: 'day ' + clsName,
18669 html: prevMonth.getDate()
18672 prevMonth.setDate(prevMonth.getDate()+1);
18675 var currentYear = this.date && this.date.getUTCFullYear();
18676 var currentMonth = this.date && this.date.getUTCMonth();
18678 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18680 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18681 v.removeClass('active');
18683 if(currentYear === year && k === currentMonth){
18684 v.addClass('active');
18687 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18688 v.addClass('disabled');
18694 year = parseInt(year/10, 10) * 10;
18696 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18698 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18701 for (var i = -1; i < 11; i++) {
18702 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18704 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18712 showMode: function(dir)
18715 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18718 Roo.each(this.picker().select('>div',true).elements, function(v){
18719 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18722 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18727 if(this.isInline) {
18731 this.picker().removeClass(['bottom', 'top']);
18733 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18735 * place to the top of element!
18739 this.picker().addClass('top');
18740 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18745 this.picker().addClass('bottom');
18747 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18750 parseDate : function(value)
18752 if(!value || value instanceof Date){
18755 var v = Date.parseDate(value, this.format);
18756 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18757 v = Date.parseDate(value, 'Y-m-d');
18759 if(!v && this.altFormats){
18760 if(!this.altFormatsArray){
18761 this.altFormatsArray = this.altFormats.split("|");
18763 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18764 v = Date.parseDate(value, this.altFormatsArray[i]);
18770 formatDate : function(date, fmt)
18772 return (!date || !(date instanceof Date)) ?
18773 date : date.dateFormat(fmt || this.format);
18776 onFocus : function()
18778 Roo.bootstrap.DateField.superclass.onFocus.call(this);
18782 onBlur : function()
18784 Roo.bootstrap.DateField.superclass.onBlur.call(this);
18786 var d = this.inputEl().getValue();
18795 this.picker().show();
18799 this.fireEvent('show', this, this.date);
18804 if(this.isInline) {
18807 this.picker().hide();
18808 this.viewMode = this.startViewMode;
18811 this.fireEvent('hide', this, this.date);
18815 onMousedown: function(e)
18817 e.stopPropagation();
18818 e.preventDefault();
18823 Roo.bootstrap.DateField.superclass.keyup.call(this);
18827 setValue: function(v)
18829 if(this.fireEvent('beforeselect', this, v) !== false){
18830 var d = new Date(this.parseDate(v) ).clearTime();
18832 if(isNaN(d.getTime())){
18833 this.date = this.viewDate = '';
18834 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18838 v = this.formatDate(d);
18840 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18842 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18846 this.fireEvent('select', this, this.date);
18850 getValue: function()
18852 return this.formatDate(this.date);
18855 fireKey: function(e)
18857 if (!this.picker().isVisible()){
18858 if (e.keyCode == 27) { // allow escape to hide and re-show picker
18864 var dateChanged = false,
18866 newDate, newViewDate;
18871 e.preventDefault();
18875 if (!this.keyboardNavigation) {
18878 dir = e.keyCode == 37 ? -1 : 1;
18881 newDate = this.moveYear(this.date, dir);
18882 newViewDate = this.moveYear(this.viewDate, dir);
18883 } else if (e.shiftKey){
18884 newDate = this.moveMonth(this.date, dir);
18885 newViewDate = this.moveMonth(this.viewDate, dir);
18887 newDate = new Date(this.date);
18888 newDate.setUTCDate(this.date.getUTCDate() + dir);
18889 newViewDate = new Date(this.viewDate);
18890 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18892 if (this.dateWithinRange(newDate)){
18893 this.date = newDate;
18894 this.viewDate = newViewDate;
18895 this.setValue(this.formatDate(this.date));
18897 e.preventDefault();
18898 dateChanged = true;
18903 if (!this.keyboardNavigation) {
18906 dir = e.keyCode == 38 ? -1 : 1;
18908 newDate = this.moveYear(this.date, dir);
18909 newViewDate = this.moveYear(this.viewDate, dir);
18910 } else if (e.shiftKey){
18911 newDate = this.moveMonth(this.date, dir);
18912 newViewDate = this.moveMonth(this.viewDate, dir);
18914 newDate = new Date(this.date);
18915 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18916 newViewDate = new Date(this.viewDate);
18917 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18919 if (this.dateWithinRange(newDate)){
18920 this.date = newDate;
18921 this.viewDate = newViewDate;
18922 this.setValue(this.formatDate(this.date));
18924 e.preventDefault();
18925 dateChanged = true;
18929 this.setValue(this.formatDate(this.date));
18931 e.preventDefault();
18934 this.setValue(this.formatDate(this.date));
18948 onClick: function(e)
18950 e.stopPropagation();
18951 e.preventDefault();
18953 var target = e.getTarget();
18955 if(target.nodeName.toLowerCase() === 'i'){
18956 target = Roo.get(target).dom.parentNode;
18959 var nodeName = target.nodeName;
18960 var className = target.className;
18961 var html = target.innerHTML;
18962 //Roo.log(nodeName);
18964 switch(nodeName.toLowerCase()) {
18966 switch(className) {
18972 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
18973 switch(this.viewMode){
18975 this.viewDate = this.moveMonth(this.viewDate, dir);
18979 this.viewDate = this.moveYear(this.viewDate, dir);
18985 var date = new Date();
18986 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
18988 this.setValue(this.formatDate(this.date));
18995 if (className.indexOf('disabled') < 0) {
18996 this.viewDate.setUTCDate(1);
18997 if (className.indexOf('month') > -1) {
18998 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19000 var year = parseInt(html, 10) || 0;
19001 this.viewDate.setUTCFullYear(year);
19005 if(this.singleMode){
19006 this.setValue(this.formatDate(this.viewDate));
19017 //Roo.log(className);
19018 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19019 var day = parseInt(html, 10) || 1;
19020 var year = this.viewDate.getUTCFullYear(),
19021 month = this.viewDate.getUTCMonth();
19023 if (className.indexOf('old') > -1) {
19030 } else if (className.indexOf('new') > -1) {
19038 //Roo.log([year,month,day]);
19039 this.date = this.UTCDate(year, month, day,0,0,0,0);
19040 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19042 //Roo.log(this.formatDate(this.date));
19043 this.setValue(this.formatDate(this.date));
19050 setStartDate: function(startDate)
19052 this.startDate = startDate || -Infinity;
19053 if (this.startDate !== -Infinity) {
19054 this.startDate = this.parseDate(this.startDate);
19057 this.updateNavArrows();
19060 setEndDate: function(endDate)
19062 this.endDate = endDate || Infinity;
19063 if (this.endDate !== Infinity) {
19064 this.endDate = this.parseDate(this.endDate);
19067 this.updateNavArrows();
19070 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19072 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19073 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19074 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19076 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19077 return parseInt(d, 10);
19080 this.updateNavArrows();
19083 updateNavArrows: function()
19085 if(this.singleMode){
19089 var d = new Date(this.viewDate),
19090 year = d.getUTCFullYear(),
19091 month = d.getUTCMonth();
19093 Roo.each(this.picker().select('.prev', true).elements, function(v){
19095 switch (this.viewMode) {
19098 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19104 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19111 Roo.each(this.picker().select('.next', true).elements, function(v){
19113 switch (this.viewMode) {
19116 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19122 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19130 moveMonth: function(date, dir)
19135 var new_date = new Date(date.valueOf()),
19136 day = new_date.getUTCDate(),
19137 month = new_date.getUTCMonth(),
19138 mag = Math.abs(dir),
19140 dir = dir > 0 ? 1 : -1;
19143 // If going back one month, make sure month is not current month
19144 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19146 return new_date.getUTCMonth() == month;
19148 // If going forward one month, make sure month is as expected
19149 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19151 return new_date.getUTCMonth() != new_month;
19153 new_month = month + dir;
19154 new_date.setUTCMonth(new_month);
19155 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19156 if (new_month < 0 || new_month > 11) {
19157 new_month = (new_month + 12) % 12;
19160 // For magnitudes >1, move one month at a time...
19161 for (var i=0; i<mag; i++) {
19162 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19163 new_date = this.moveMonth(new_date, dir);
19165 // ...then reset the day, keeping it in the new month
19166 new_month = new_date.getUTCMonth();
19167 new_date.setUTCDate(day);
19169 return new_month != new_date.getUTCMonth();
19172 // Common date-resetting loop -- if date is beyond end of month, make it
19175 new_date.setUTCDate(--day);
19176 new_date.setUTCMonth(new_month);
19181 moveYear: function(date, dir)
19183 return this.moveMonth(date, dir*12);
19186 dateWithinRange: function(date)
19188 return date >= this.startDate && date <= this.endDate;
19194 this.picker().remove();
19197 validateValue : function(value)
19199 if(this.getVisibilityEl().hasClass('hidden')){
19203 if(value.length < 1) {
19204 if(this.allowBlank){
19210 if(value.length < this.minLength){
19213 if(value.length > this.maxLength){
19217 var vt = Roo.form.VTypes;
19218 if(!vt[this.vtype](value, this)){
19222 if(typeof this.validator == "function"){
19223 var msg = this.validator(value);
19229 if(this.regex && !this.regex.test(value)){
19233 if(typeof(this.parseDate(value)) == 'undefined'){
19237 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19241 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19249 setVisible : function(visible)
19255 this.getEl().removeClass('hidden');
19261 this.getEl().addClass('hidden');
19266 Roo.apply(Roo.bootstrap.DateField, {
19277 html: '<i class="fa fa-arrow-left"/>'
19287 html: '<i class="fa fa-arrow-right"/>'
19329 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19330 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19331 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19332 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19333 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19346 navFnc: 'FullYear',
19351 navFnc: 'FullYear',
19356 Roo.apply(Roo.bootstrap.DateField, {
19360 cls: 'datepicker dropdown-menu roo-dynamic',
19364 cls: 'datepicker-days',
19368 cls: 'table-condensed',
19370 Roo.bootstrap.DateField.head,
19374 Roo.bootstrap.DateField.footer
19381 cls: 'datepicker-months',
19385 cls: 'table-condensed',
19387 Roo.bootstrap.DateField.head,
19388 Roo.bootstrap.DateField.content,
19389 Roo.bootstrap.DateField.footer
19396 cls: 'datepicker-years',
19400 cls: 'table-condensed',
19402 Roo.bootstrap.DateField.head,
19403 Roo.bootstrap.DateField.content,
19404 Roo.bootstrap.DateField.footer
19423 * @class Roo.bootstrap.TimeField
19424 * @extends Roo.bootstrap.Input
19425 * Bootstrap DateField class
19429 * Create a new TimeField
19430 * @param {Object} config The config object
19433 Roo.bootstrap.TimeField = function(config){
19434 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19438 * Fires when this field show.
19439 * @param {Roo.bootstrap.DateField} thisthis
19440 * @param {Mixed} date The date value
19445 * Fires when this field hide.
19446 * @param {Roo.bootstrap.DateField} this
19447 * @param {Mixed} date The date value
19452 * Fires when select a date.
19453 * @param {Roo.bootstrap.DateField} this
19454 * @param {Mixed} date The date value
19460 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19463 * @cfg {String} format
19464 * The default time format string which can be overriden for localization support. The format must be
19465 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19469 onRender: function(ct, position)
19472 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19474 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19476 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19478 this.pop = this.picker().select('>.datepicker-time',true).first();
19479 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19481 this.picker().on('mousedown', this.onMousedown, this);
19482 this.picker().on('click', this.onClick, this);
19484 this.picker().addClass('datepicker-dropdown');
19489 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19490 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19491 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19492 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19493 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19494 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19498 fireKey: function(e){
19499 if (!this.picker().isVisible()){
19500 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19506 e.preventDefault();
19514 this.onTogglePeriod();
19517 this.onIncrementMinutes();
19520 this.onDecrementMinutes();
19529 onClick: function(e) {
19530 e.stopPropagation();
19531 e.preventDefault();
19534 picker : function()
19536 return this.el.select('.datepicker', true).first();
19539 fillTime: function()
19541 var time = this.pop.select('tbody', true).first();
19543 time.dom.innerHTML = '';
19558 cls: 'hours-up glyphicon glyphicon-chevron-up'
19578 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19599 cls: 'timepicker-hour',
19614 cls: 'timepicker-minute',
19629 cls: 'btn btn-primary period',
19651 cls: 'hours-down glyphicon glyphicon-chevron-down'
19671 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19689 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19696 var hours = this.time.getHours();
19697 var minutes = this.time.getMinutes();
19710 hours = hours - 12;
19714 hours = '0' + hours;
19718 minutes = '0' + minutes;
19721 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19722 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19723 this.pop.select('button', true).first().dom.innerHTML = period;
19729 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19731 var cls = ['bottom'];
19733 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19740 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19745 this.picker().addClass(cls.join('-'));
19749 Roo.each(cls, function(c){
19751 _this.picker().setTop(_this.inputEl().getHeight());
19755 _this.picker().setTop(0 - _this.picker().getHeight());
19760 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19764 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19771 onFocus : function()
19773 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19777 onBlur : function()
19779 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19785 this.picker().show();
19790 this.fireEvent('show', this, this.date);
19795 this.picker().hide();
19798 this.fireEvent('hide', this, this.date);
19801 setTime : function()
19804 this.setValue(this.time.format(this.format));
19806 this.fireEvent('select', this, this.date);
19811 onMousedown: function(e){
19812 e.stopPropagation();
19813 e.preventDefault();
19816 onIncrementHours: function()
19818 Roo.log('onIncrementHours');
19819 this.time = this.time.add(Date.HOUR, 1);
19824 onDecrementHours: function()
19826 Roo.log('onDecrementHours');
19827 this.time = this.time.add(Date.HOUR, -1);
19831 onIncrementMinutes: function()
19833 Roo.log('onIncrementMinutes');
19834 this.time = this.time.add(Date.MINUTE, 1);
19838 onDecrementMinutes: function()
19840 Roo.log('onDecrementMinutes');
19841 this.time = this.time.add(Date.MINUTE, -1);
19845 onTogglePeriod: function()
19847 Roo.log('onTogglePeriod');
19848 this.time = this.time.add(Date.HOUR, 12);
19855 Roo.apply(Roo.bootstrap.TimeField, {
19885 cls: 'btn btn-info ok',
19897 Roo.apply(Roo.bootstrap.TimeField, {
19901 cls: 'datepicker dropdown-menu',
19905 cls: 'datepicker-time',
19909 cls: 'table-condensed',
19911 Roo.bootstrap.TimeField.content,
19912 Roo.bootstrap.TimeField.footer
19931 * @class Roo.bootstrap.MonthField
19932 * @extends Roo.bootstrap.Input
19933 * Bootstrap MonthField class
19935 * @cfg {String} language default en
19938 * Create a new MonthField
19939 * @param {Object} config The config object
19942 Roo.bootstrap.MonthField = function(config){
19943 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19948 * Fires when this field show.
19949 * @param {Roo.bootstrap.MonthField} this
19950 * @param {Mixed} date The date value
19955 * Fires when this field hide.
19956 * @param {Roo.bootstrap.MonthField} this
19957 * @param {Mixed} date The date value
19962 * Fires when select a date.
19963 * @param {Roo.bootstrap.MonthField} this
19964 * @param {String} oldvalue The old value
19965 * @param {String} newvalue The new value
19971 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
19973 onRender: function(ct, position)
19976 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
19978 this.language = this.language || 'en';
19979 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
19980 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
19982 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
19983 this.isInline = false;
19984 this.isInput = true;
19985 this.component = this.el.select('.add-on', true).first() || false;
19986 this.component = (this.component && this.component.length === 0) ? false : this.component;
19987 this.hasInput = this.component && this.inputEL().length;
19989 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
19991 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19993 this.picker().on('mousedown', this.onMousedown, this);
19994 this.picker().on('click', this.onClick, this);
19996 this.picker().addClass('datepicker-dropdown');
19998 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19999 v.setStyle('width', '189px');
20006 if(this.isInline) {
20012 setValue: function(v, suppressEvent)
20014 var o = this.getValue();
20016 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20020 if(suppressEvent !== true){
20021 this.fireEvent('select', this, o, v);
20026 getValue: function()
20031 onClick: function(e)
20033 e.stopPropagation();
20034 e.preventDefault();
20036 var target = e.getTarget();
20038 if(target.nodeName.toLowerCase() === 'i'){
20039 target = Roo.get(target).dom.parentNode;
20042 var nodeName = target.nodeName;
20043 var className = target.className;
20044 var html = target.innerHTML;
20046 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20050 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20052 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20058 picker : function()
20060 return this.pickerEl;
20063 fillMonths: function()
20066 var months = this.picker().select('>.datepicker-months td', true).first();
20068 months.dom.innerHTML = '';
20074 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20077 months.createChild(month);
20086 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20087 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20090 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20091 e.removeClass('active');
20093 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20094 e.addClass('active');
20101 if(this.isInline) {
20105 this.picker().removeClass(['bottom', 'top']);
20107 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20109 * place to the top of element!
20113 this.picker().addClass('top');
20114 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20119 this.picker().addClass('bottom');
20121 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20124 onFocus : function()
20126 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20130 onBlur : function()
20132 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20134 var d = this.inputEl().getValue();
20143 this.picker().show();
20144 this.picker().select('>.datepicker-months', true).first().show();
20148 this.fireEvent('show', this, this.date);
20153 if(this.isInline) {
20156 this.picker().hide();
20157 this.fireEvent('hide', this, this.date);
20161 onMousedown: function(e)
20163 e.stopPropagation();
20164 e.preventDefault();
20169 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20173 fireKey: function(e)
20175 if (!this.picker().isVisible()){
20176 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20187 e.preventDefault();
20191 dir = e.keyCode == 37 ? -1 : 1;
20193 this.vIndex = this.vIndex + dir;
20195 if(this.vIndex < 0){
20199 if(this.vIndex > 11){
20203 if(isNaN(this.vIndex)){
20207 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20213 dir = e.keyCode == 38 ? -1 : 1;
20215 this.vIndex = this.vIndex + dir * 4;
20217 if(this.vIndex < 0){
20221 if(this.vIndex > 11){
20225 if(isNaN(this.vIndex)){
20229 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20234 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20235 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20239 e.preventDefault();
20242 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20243 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20259 this.picker().remove();
20264 Roo.apply(Roo.bootstrap.MonthField, {
20283 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20284 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20289 Roo.apply(Roo.bootstrap.MonthField, {
20293 cls: 'datepicker dropdown-menu roo-dynamic',
20297 cls: 'datepicker-months',
20301 cls: 'table-condensed',
20303 Roo.bootstrap.DateField.content
20323 * @class Roo.bootstrap.CheckBox
20324 * @extends Roo.bootstrap.Input
20325 * Bootstrap CheckBox class
20327 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20328 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20329 * @cfg {String} boxLabel The text that appears beside the checkbox
20330 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20331 * @cfg {Boolean} checked initnal the element
20332 * @cfg {Boolean} inline inline the element (default false)
20333 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20334 * @cfg {String} tooltip label tooltip
20337 * Create a new CheckBox
20338 * @param {Object} config The config object
20341 Roo.bootstrap.CheckBox = function(config){
20342 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20347 * Fires when the element is checked or unchecked.
20348 * @param {Roo.bootstrap.CheckBox} this This input
20349 * @param {Boolean} checked The new checked value
20354 * Fires when the element is click.
20355 * @param {Roo.bootstrap.CheckBox} this This input
20362 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20364 inputType: 'checkbox',
20373 getAutoCreate : function()
20375 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20381 cfg.cls = 'form-group ' + this.inputType; //input-group
20384 cfg.cls += ' ' + this.inputType + '-inline';
20390 type : this.inputType,
20391 value : this.inputValue,
20392 cls : 'roo-' + this.inputType, //'form-box',
20393 placeholder : this.placeholder || ''
20397 if(this.inputType != 'radio'){
20401 cls : 'roo-hidden-value',
20402 value : this.checked ? this.inputValue : this.valueOff
20407 if (this.weight) { // Validity check?
20408 cfg.cls += " " + this.inputType + "-" + this.weight;
20411 if (this.disabled) {
20412 input.disabled=true;
20416 input.checked = this.checked;
20421 input.name = this.name;
20423 if(this.inputType != 'radio'){
20424 hidden.name = this.name;
20425 input.name = '_hidden_' + this.name;
20430 input.cls += ' input-' + this.size;
20435 ['xs','sm','md','lg'].map(function(size){
20436 if (settings[size]) {
20437 cfg.cls += ' col-' + size + '-' + settings[size];
20441 var inputblock = input;
20443 if (this.before || this.after) {
20446 cls : 'input-group',
20451 inputblock.cn.push({
20453 cls : 'input-group-addon',
20458 inputblock.cn.push(input);
20460 if(this.inputType != 'radio'){
20461 inputblock.cn.push(hidden);
20465 inputblock.cn.push({
20467 cls : 'input-group-addon',
20474 if (align ==='left' && this.fieldLabel.length) {
20475 // Roo.log("left and has label");
20480 cls : 'control-label',
20481 html : this.fieldLabel
20491 if(this.labelWidth > 12){
20492 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20495 if(this.labelWidth < 13 && this.labelmd == 0){
20496 this.labelmd = this.labelWidth;
20499 if(this.labellg > 0){
20500 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20501 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20504 if(this.labelmd > 0){
20505 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20506 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20509 if(this.labelsm > 0){
20510 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20511 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20514 if(this.labelxs > 0){
20515 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20516 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20519 } else if ( this.fieldLabel.length) {
20520 // Roo.log(" label");
20524 tag: this.boxLabel ? 'span' : 'label',
20526 cls: 'control-label box-input-label',
20527 //cls : 'input-group-addon',
20528 html : this.fieldLabel
20537 // Roo.log(" no label && no align");
20538 cfg.cn = [ inputblock ] ;
20544 var boxLabelCfg = {
20546 //'for': id, // box label is handled by onclick - so no for...
20548 html: this.boxLabel
20552 boxLabelCfg.tooltip = this.tooltip;
20555 cfg.cn.push(boxLabelCfg);
20558 if(this.inputType != 'radio'){
20559 cfg.cn.push(hidden);
20567 * return the real input element.
20569 inputEl: function ()
20571 return this.el.select('input.roo-' + this.inputType,true).first();
20573 hiddenEl: function ()
20575 return this.el.select('input.roo-hidden-value',true).first();
20578 labelEl: function()
20580 return this.el.select('label.control-label',true).first();
20582 /* depricated... */
20586 return this.labelEl();
20589 boxLabelEl: function()
20591 return this.el.select('label.box-label',true).first();
20594 initEvents : function()
20596 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20598 this.inputEl().on('click', this.onClick, this);
20600 if (this.boxLabel) {
20601 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20604 this.startValue = this.getValue();
20607 Roo.bootstrap.CheckBox.register(this);
20611 onClick : function(e)
20613 if(this.fireEvent('click', this, e) !== false){
20614 this.setChecked(!this.checked);
20619 setChecked : function(state,suppressEvent)
20621 this.startValue = this.getValue();
20623 if(this.inputType == 'radio'){
20625 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20626 e.dom.checked = false;
20629 this.inputEl().dom.checked = true;
20631 this.inputEl().dom.value = this.inputValue;
20633 if(suppressEvent !== true){
20634 this.fireEvent('check', this, true);
20642 this.checked = state;
20644 this.inputEl().dom.checked = state;
20647 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20649 if(suppressEvent !== true){
20650 this.fireEvent('check', this, state);
20656 getValue : function()
20658 if(this.inputType == 'radio'){
20659 return this.getGroupValue();
20662 return this.hiddenEl().dom.value;
20666 getGroupValue : function()
20668 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20672 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20675 setValue : function(v,suppressEvent)
20677 if(this.inputType == 'radio'){
20678 this.setGroupValue(v, suppressEvent);
20682 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20687 setGroupValue : function(v, suppressEvent)
20689 this.startValue = this.getValue();
20691 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20692 e.dom.checked = false;
20694 if(e.dom.value == v){
20695 e.dom.checked = true;
20699 if(suppressEvent !== true){
20700 this.fireEvent('check', this, true);
20708 validate : function()
20710 if(this.getVisibilityEl().hasClass('hidden')){
20716 (this.inputType == 'radio' && this.validateRadio()) ||
20717 (this.inputType == 'checkbox' && this.validateCheckbox())
20723 this.markInvalid();
20727 validateRadio : function()
20729 if(this.getVisibilityEl().hasClass('hidden')){
20733 if(this.allowBlank){
20739 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20740 if(!e.dom.checked){
20752 validateCheckbox : function()
20755 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20756 //return (this.getValue() == this.inputValue) ? true : false;
20759 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20767 for(var i in group){
20768 if(group[i].el.isVisible(true)){
20776 for(var i in group){
20781 r = (group[i].getValue() == group[i].inputValue) ? true : false;
20788 * Mark this field as valid
20790 markValid : function()
20794 this.fireEvent('valid', this);
20796 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20799 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20806 if(this.inputType == 'radio'){
20807 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20808 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20809 e.findParent('.form-group', false, true).addClass(_this.validClass);
20816 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20817 this.el.findParent('.form-group', false, true).addClass(this.validClass);
20821 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20827 for(var i in group){
20828 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20829 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20834 * Mark this field as invalid
20835 * @param {String} msg The validation message
20837 markInvalid : function(msg)
20839 if(this.allowBlank){
20845 this.fireEvent('invalid', this, msg);
20847 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20850 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20854 label.markInvalid();
20857 if(this.inputType == 'radio'){
20858 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20859 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20860 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20867 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20868 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20872 var group = Roo.bootstrap.CheckBox.get(this.groupId);
20878 for(var i in group){
20879 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20880 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20885 clearInvalid : function()
20887 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20889 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20891 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20893 if (label && label.iconEl) {
20894 label.iconEl.removeClass(label.validClass);
20895 label.iconEl.removeClass(label.invalidClass);
20899 disable : function()
20901 if(this.inputType != 'radio'){
20902 Roo.bootstrap.CheckBox.superclass.disable.call(this);
20909 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20910 _this.getActionEl().addClass(this.disabledClass);
20911 e.dom.disabled = true;
20915 this.disabled = true;
20916 this.fireEvent("disable", this);
20920 enable : function()
20922 if(this.inputType != 'radio'){
20923 Roo.bootstrap.CheckBox.superclass.enable.call(this);
20930 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20931 _this.getActionEl().removeClass(this.disabledClass);
20932 e.dom.disabled = false;
20936 this.disabled = false;
20937 this.fireEvent("enable", this);
20941 setBoxLabel : function(v)
20946 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20952 Roo.apply(Roo.bootstrap.CheckBox, {
20957 * register a CheckBox Group
20958 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20960 register : function(checkbox)
20962 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20963 this.groups[checkbox.groupId] = {};
20966 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
20970 this.groups[checkbox.groupId][checkbox.name] = checkbox;
20974 * fetch a CheckBox Group based on the group ID
20975 * @param {string} the group ID
20976 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
20978 get: function(groupId) {
20979 if (typeof(this.groups[groupId]) == 'undefined') {
20983 return this.groups[groupId] ;
20996 * @class Roo.bootstrap.Radio
20997 * @extends Roo.bootstrap.Component
20998 * Bootstrap Radio class
20999 * @cfg {String} boxLabel - the label associated
21000 * @cfg {String} value - the value of radio
21003 * Create a new Radio
21004 * @param {Object} config The config object
21006 Roo.bootstrap.Radio = function(config){
21007 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21011 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21017 getAutoCreate : function()
21021 cls : 'form-group radio',
21026 html : this.boxLabel
21034 initEvents : function()
21036 this.parent().register(this);
21038 this.el.on('click', this.onClick, this);
21042 onClick : function(e)
21044 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21045 this.setChecked(true);
21049 setChecked : function(state, suppressEvent)
21051 this.parent().setValue(this.value, suppressEvent);
21055 setBoxLabel : function(v)
21060 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21075 * @class Roo.bootstrap.SecurePass
21076 * @extends Roo.bootstrap.Input
21077 * Bootstrap SecurePass class
21081 * Create a new SecurePass
21082 * @param {Object} config The config object
21085 Roo.bootstrap.SecurePass = function (config) {
21086 // these go here, so the translation tool can replace them..
21088 PwdEmpty: "Please type a password, and then retype it to confirm.",
21089 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21090 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21091 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21092 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21093 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21094 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21095 TooWeak: "Your password is Too Weak."
21097 this.meterLabel = "Password strength:";
21098 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21099 this.meterClass = [
21100 "roo-password-meter-tooweak",
21101 "roo-password-meter-weak",
21102 "roo-password-meter-medium",
21103 "roo-password-meter-strong",
21104 "roo-password-meter-grey"
21109 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21112 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21114 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21116 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21117 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21118 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21119 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21120 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21121 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21122 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21132 * @cfg {String/Object} Label for the strength meter (defaults to
21133 * 'Password strength:')
21138 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21139 * ['Weak', 'Medium', 'Strong'])
21142 pwdStrengths: false,
21155 initEvents: function ()
21157 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21159 if (this.el.is('input[type=password]') && Roo.isSafari) {
21160 this.el.on('keydown', this.SafariOnKeyDown, this);
21163 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21166 onRender: function (ct, position)
21168 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21169 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21170 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21172 this.trigger.createChild({
21177 cls: 'roo-password-meter-grey col-xs-12',
21180 //width: this.meterWidth + 'px'
21184 cls: 'roo-password-meter-text'
21190 if (this.hideTrigger) {
21191 this.trigger.setDisplayed(false);
21193 this.setSize(this.width || '', this.height || '');
21196 onDestroy: function ()
21198 if (this.trigger) {
21199 this.trigger.removeAllListeners();
21200 this.trigger.remove();
21203 this.wrap.remove();
21205 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21208 checkStrength: function ()
21210 var pwd = this.inputEl().getValue();
21211 if (pwd == this._lastPwd) {
21216 if (this.ClientSideStrongPassword(pwd)) {
21218 } else if (this.ClientSideMediumPassword(pwd)) {
21220 } else if (this.ClientSideWeakPassword(pwd)) {
21226 Roo.log('strength1: ' + strength);
21228 //var pm = this.trigger.child('div/div/div').dom;
21229 var pm = this.trigger.child('div/div');
21230 pm.removeClass(this.meterClass);
21231 pm.addClass(this.meterClass[strength]);
21234 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21236 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21238 this._lastPwd = pwd;
21242 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21244 this._lastPwd = '';
21246 var pm = this.trigger.child('div/div');
21247 pm.removeClass(this.meterClass);
21248 pm.addClass('roo-password-meter-grey');
21251 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21254 this.inputEl().dom.type='password';
21257 validateValue: function (value)
21260 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21263 if (value.length == 0) {
21264 if (this.allowBlank) {
21265 this.clearInvalid();
21269 this.markInvalid(this.errors.PwdEmpty);
21270 this.errorMsg = this.errors.PwdEmpty;
21278 if ('[\x21-\x7e]*'.match(value)) {
21279 this.markInvalid(this.errors.PwdBadChar);
21280 this.errorMsg = this.errors.PwdBadChar;
21283 if (value.length < 6) {
21284 this.markInvalid(this.errors.PwdShort);
21285 this.errorMsg = this.errors.PwdShort;
21288 if (value.length > 16) {
21289 this.markInvalid(this.errors.PwdLong);
21290 this.errorMsg = this.errors.PwdLong;
21294 if (this.ClientSideStrongPassword(value)) {
21296 } else if (this.ClientSideMediumPassword(value)) {
21298 } else if (this.ClientSideWeakPassword(value)) {
21305 if (strength < 2) {
21306 //this.markInvalid(this.errors.TooWeak);
21307 this.errorMsg = this.errors.TooWeak;
21312 console.log('strength2: ' + strength);
21314 //var pm = this.trigger.child('div/div/div').dom;
21316 var pm = this.trigger.child('div/div');
21317 pm.removeClass(this.meterClass);
21318 pm.addClass(this.meterClass[strength]);
21320 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21322 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21324 this.errorMsg = '';
21328 CharacterSetChecks: function (type)
21331 this.fResult = false;
21334 isctype: function (character, type)
21337 case this.kCapitalLetter:
21338 if (character >= 'A' && character <= 'Z') {
21343 case this.kSmallLetter:
21344 if (character >= 'a' && character <= 'z') {
21350 if (character >= '0' && character <= '9') {
21355 case this.kPunctuation:
21356 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21367 IsLongEnough: function (pwd, size)
21369 return !(pwd == null || isNaN(size) || pwd.length < size);
21372 SpansEnoughCharacterSets: function (word, nb)
21374 if (!this.IsLongEnough(word, nb))
21379 var characterSetChecks = new Array(
21380 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21381 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21384 for (var index = 0; index < word.length; ++index) {
21385 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21386 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21387 characterSetChecks[nCharSet].fResult = true;
21394 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21395 if (characterSetChecks[nCharSet].fResult) {
21400 if (nCharSets < nb) {
21406 ClientSideStrongPassword: function (pwd)
21408 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21411 ClientSideMediumPassword: function (pwd)
21413 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21416 ClientSideWeakPassword: function (pwd)
21418 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21421 })//<script type="text/javascript">
21424 * Based Ext JS Library 1.1.1
21425 * Copyright(c) 2006-2007, Ext JS, LLC.
21431 * @class Roo.HtmlEditorCore
21432 * @extends Roo.Component
21433 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21435 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21438 Roo.HtmlEditorCore = function(config){
21441 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21446 * @event initialize
21447 * Fires when the editor is fully initialized (including the iframe)
21448 * @param {Roo.HtmlEditorCore} this
21453 * Fires when the editor is first receives the focus. Any insertion must wait
21454 * until after this event.
21455 * @param {Roo.HtmlEditorCore} this
21459 * @event beforesync
21460 * Fires before the textarea is updated with content from the editor iframe. Return false
21461 * to cancel the sync.
21462 * @param {Roo.HtmlEditorCore} this
21463 * @param {String} html
21467 * @event beforepush
21468 * Fires before the iframe editor is updated with content from the textarea. Return false
21469 * to cancel the push.
21470 * @param {Roo.HtmlEditorCore} this
21471 * @param {String} html
21476 * Fires when the textarea is updated with content from the editor iframe.
21477 * @param {Roo.HtmlEditorCore} this
21478 * @param {String} html
21483 * Fires when the iframe editor is updated with content from the textarea.
21484 * @param {Roo.HtmlEditorCore} this
21485 * @param {String} html
21490 * @event editorevent
21491 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21492 * @param {Roo.HtmlEditorCore} this
21498 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21500 // defaults : white / black...
21501 this.applyBlacklists();
21508 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21512 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21518 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21523 * @cfg {Number} height (in pixels)
21527 * @cfg {Number} width (in pixels)
21532 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21535 stylesheets: false,
21540 // private properties
21541 validationEvent : false,
21543 initialized : false,
21545 sourceEditMode : false,
21546 onFocus : Roo.emptyFn,
21548 hideMode:'offsets',
21552 // blacklist + whitelisted elements..
21559 * Protected method that will not generally be called directly. It
21560 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21561 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21563 getDocMarkup : function(){
21567 // inherit styels from page...??
21568 if (this.stylesheets === false) {
21570 Roo.get(document.head).select('style').each(function(node) {
21571 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21574 Roo.get(document.head).select('link').each(function(node) {
21575 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21578 } else if (!this.stylesheets.length) {
21580 st = '<style type="text/css">' +
21581 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21584 st = '<style type="text/css">' +
21589 st += '<style type="text/css">' +
21590 'IMG { cursor: pointer } ' +
21593 var cls = 'roo-htmleditor-body';
21595 if(this.bodyCls.length){
21596 cls += ' ' + this.bodyCls;
21599 return '<html><head>' + st +
21600 //<style type="text/css">' +
21601 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21603 ' </head><body class="' + cls + '"></body></html>';
21607 onRender : function(ct, position)
21610 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21611 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21614 this.el.dom.style.border = '0 none';
21615 this.el.dom.setAttribute('tabIndex', -1);
21616 this.el.addClass('x-hidden hide');
21620 if(Roo.isIE){ // fix IE 1px bogus margin
21621 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21625 this.frameId = Roo.id();
21629 var iframe = this.owner.wrap.createChild({
21631 cls: 'form-control', // bootstrap..
21633 name: this.frameId,
21634 frameBorder : 'no',
21635 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21640 this.iframe = iframe.dom;
21642 this.assignDocWin();
21644 this.doc.designMode = 'on';
21647 this.doc.write(this.getDocMarkup());
21651 var task = { // must defer to wait for browser to be ready
21653 //console.log("run task?" + this.doc.readyState);
21654 this.assignDocWin();
21655 if(this.doc.body || this.doc.readyState == 'complete'){
21657 this.doc.designMode="on";
21661 Roo.TaskMgr.stop(task);
21662 this.initEditor.defer(10, this);
21669 Roo.TaskMgr.start(task);
21674 onResize : function(w, h)
21676 Roo.log('resize: ' +w + ',' + h );
21677 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21681 if(typeof w == 'number'){
21683 this.iframe.style.width = w + 'px';
21685 if(typeof h == 'number'){
21687 this.iframe.style.height = h + 'px';
21689 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21696 * Toggles the editor between standard and source edit mode.
21697 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21699 toggleSourceEdit : function(sourceEditMode){
21701 this.sourceEditMode = sourceEditMode === true;
21703 if(this.sourceEditMode){
21705 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21708 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21709 //this.iframe.className = '';
21712 //this.setSize(this.owner.wrap.getSize());
21713 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21720 * Protected method that will not generally be called directly. If you need/want
21721 * custom HTML cleanup, this is the method you should override.
21722 * @param {String} html The HTML to be cleaned
21723 * return {String} The cleaned HTML
21725 cleanHtml : function(html){
21726 html = String(html);
21727 if(html.length > 5){
21728 if(Roo.isSafari){ // strip safari nonsense
21729 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21732 if(html == ' '){
21739 * HTML Editor -> Textarea
21740 * Protected method that will not generally be called directly. Syncs the contents
21741 * of the editor iframe with the textarea.
21743 syncValue : function(){
21744 if(this.initialized){
21745 var bd = (this.doc.body || this.doc.documentElement);
21746 //this.cleanUpPaste(); -- this is done else where and causes havoc..
21747 var html = bd.innerHTML;
21749 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21750 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21752 html = '<div style="'+m[0]+'">' + html + '</div>';
21755 html = this.cleanHtml(html);
21756 // fix up the special chars.. normaly like back quotes in word...
21757 // however we do not want to do this with chinese..
21758 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21759 var cc = b.charCodeAt();
21761 (cc >= 0x4E00 && cc < 0xA000 ) ||
21762 (cc >= 0x3400 && cc < 0x4E00 ) ||
21763 (cc >= 0xf900 && cc < 0xfb00 )
21769 if(this.owner.fireEvent('beforesync', this, html) !== false){
21770 this.el.dom.value = html;
21771 this.owner.fireEvent('sync', this, html);
21777 * Protected method that will not generally be called directly. Pushes the value of the textarea
21778 * into the iframe editor.
21780 pushValue : function(){
21781 if(this.initialized){
21782 var v = this.el.dom.value.trim();
21784 // if(v.length < 1){
21788 if(this.owner.fireEvent('beforepush', this, v) !== false){
21789 var d = (this.doc.body || this.doc.documentElement);
21791 this.cleanUpPaste();
21792 this.el.dom.value = d.innerHTML;
21793 this.owner.fireEvent('push', this, v);
21799 deferFocus : function(){
21800 this.focus.defer(10, this);
21804 focus : function(){
21805 if(this.win && !this.sourceEditMode){
21812 assignDocWin: function()
21814 var iframe = this.iframe;
21817 this.doc = iframe.contentWindow.document;
21818 this.win = iframe.contentWindow;
21820 // if (!Roo.get(this.frameId)) {
21823 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21824 // this.win = Roo.get(this.frameId).dom.contentWindow;
21826 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21830 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21831 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21836 initEditor : function(){
21837 //console.log("INIT EDITOR");
21838 this.assignDocWin();
21842 this.doc.designMode="on";
21844 this.doc.write(this.getDocMarkup());
21847 var dbody = (this.doc.body || this.doc.documentElement);
21848 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21849 // this copies styles from the containing element into thsi one..
21850 // not sure why we need all of this..
21851 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21853 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21854 //ss['background-attachment'] = 'fixed'; // w3c
21855 dbody.bgProperties = 'fixed'; // ie
21856 //Roo.DomHelper.applyStyles(dbody, ss);
21857 Roo.EventManager.on(this.doc, {
21858 //'mousedown': this.onEditorEvent,
21859 'mouseup': this.onEditorEvent,
21860 'dblclick': this.onEditorEvent,
21861 'click': this.onEditorEvent,
21862 'keyup': this.onEditorEvent,
21867 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21869 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21870 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21872 this.initialized = true;
21874 this.owner.fireEvent('initialize', this);
21879 onDestroy : function(){
21885 //for (var i =0; i < this.toolbars.length;i++) {
21886 // // fixme - ask toolbars for heights?
21887 // this.toolbars[i].onDestroy();
21890 //this.wrap.dom.innerHTML = '';
21891 //this.wrap.remove();
21896 onFirstFocus : function(){
21898 this.assignDocWin();
21901 this.activated = true;
21904 if(Roo.isGecko){ // prevent silly gecko errors
21906 var s = this.win.getSelection();
21907 if(!s.focusNode || s.focusNode.nodeType != 3){
21908 var r = s.getRangeAt(0);
21909 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21914 this.execCmd('useCSS', true);
21915 this.execCmd('styleWithCSS', false);
21918 this.owner.fireEvent('activate', this);
21922 adjustFont: function(btn){
21923 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21924 //if(Roo.isSafari){ // safari
21927 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21928 if(Roo.isSafari){ // safari
21929 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21930 v = (v < 10) ? 10 : v;
21931 v = (v > 48) ? 48 : v;
21932 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21937 v = Math.max(1, v+adjust);
21939 this.execCmd('FontSize', v );
21942 onEditorEvent : function(e)
21944 this.owner.fireEvent('editorevent', this, e);
21945 // this.updateToolbar();
21946 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21949 insertTag : function(tg)
21951 // could be a bit smarter... -> wrap the current selected tRoo..
21952 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21954 range = this.createRange(this.getSelection());
21955 var wrappingNode = this.doc.createElement(tg.toLowerCase());
21956 wrappingNode.appendChild(range.extractContents());
21957 range.insertNode(wrappingNode);
21964 this.execCmd("formatblock", tg);
21968 insertText : function(txt)
21972 var range = this.createRange();
21973 range.deleteContents();
21974 //alert(Sender.getAttribute('label'));
21976 range.insertNode(this.doc.createTextNode(txt));
21982 * Executes a Midas editor command on the editor document and performs necessary focus and
21983 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
21984 * @param {String} cmd The Midas command
21985 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
21987 relayCmd : function(cmd, value){
21989 this.execCmd(cmd, value);
21990 this.owner.fireEvent('editorevent', this);
21991 //this.updateToolbar();
21992 this.owner.deferFocus();
21996 * Executes a Midas editor command directly on the editor document.
21997 * For visual commands, you should use {@link #relayCmd} instead.
21998 * <b>This should only be called after the editor is initialized.</b>
21999 * @param {String} cmd The Midas command
22000 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22002 execCmd : function(cmd, value){
22003 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22010 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22012 * @param {String} text | dom node..
22014 insertAtCursor : function(text)
22017 if(!this.activated){
22023 var r = this.doc.selection.createRange();
22034 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22038 // from jquery ui (MIT licenced)
22040 var win = this.win;
22042 if (win.getSelection && win.getSelection().getRangeAt) {
22043 range = win.getSelection().getRangeAt(0);
22044 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22045 range.insertNode(node);
22046 } else if (win.document.selection && win.document.selection.createRange) {
22047 // no firefox support
22048 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22049 win.document.selection.createRange().pasteHTML(txt);
22051 // no firefox support
22052 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22053 this.execCmd('InsertHTML', txt);
22062 mozKeyPress : function(e){
22064 var c = e.getCharCode(), cmd;
22067 c = String.fromCharCode(c).toLowerCase();
22081 this.cleanUpPaste.defer(100, this);
22089 e.preventDefault();
22097 fixKeys : function(){ // load time branching for fastest keydown performance
22099 return function(e){
22100 var k = e.getKey(), r;
22103 r = this.doc.selection.createRange();
22106 r.pasteHTML('    ');
22113 r = this.doc.selection.createRange();
22115 var target = r.parentElement();
22116 if(!target || target.tagName.toLowerCase() != 'li'){
22118 r.pasteHTML('<br />');
22124 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22125 this.cleanUpPaste.defer(100, this);
22131 }else if(Roo.isOpera){
22132 return function(e){
22133 var k = e.getKey();
22137 this.execCmd('InsertHTML','    ');
22140 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22141 this.cleanUpPaste.defer(100, this);
22146 }else if(Roo.isSafari){
22147 return function(e){
22148 var k = e.getKey();
22152 this.execCmd('InsertText','\t');
22156 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22157 this.cleanUpPaste.defer(100, this);
22165 getAllAncestors: function()
22167 var p = this.getSelectedNode();
22170 a.push(p); // push blank onto stack..
22171 p = this.getParentElement();
22175 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22179 a.push(this.doc.body);
22183 lastSelNode : false,
22186 getSelection : function()
22188 this.assignDocWin();
22189 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22192 getSelectedNode: function()
22194 // this may only work on Gecko!!!
22196 // should we cache this!!!!
22201 var range = this.createRange(this.getSelection()).cloneRange();
22204 var parent = range.parentElement();
22206 var testRange = range.duplicate();
22207 testRange.moveToElementText(parent);
22208 if (testRange.inRange(range)) {
22211 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22214 parent = parent.parentElement;
22219 // is ancestor a text element.
22220 var ac = range.commonAncestorContainer;
22221 if (ac.nodeType == 3) {
22222 ac = ac.parentNode;
22225 var ar = ac.childNodes;
22228 var other_nodes = [];
22229 var has_other_nodes = false;
22230 for (var i=0;i<ar.length;i++) {
22231 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22234 // fullly contained node.
22236 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22241 // probably selected..
22242 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22243 other_nodes.push(ar[i]);
22247 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22252 has_other_nodes = true;
22254 if (!nodes.length && other_nodes.length) {
22255 nodes= other_nodes;
22257 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22263 createRange: function(sel)
22265 // this has strange effects when using with
22266 // top toolbar - not sure if it's a great idea.
22267 //this.editor.contentWindow.focus();
22268 if (typeof sel != "undefined") {
22270 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22272 return this.doc.createRange();
22275 return this.doc.createRange();
22278 getParentElement: function()
22281 this.assignDocWin();
22282 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22284 var range = this.createRange(sel);
22287 var p = range.commonAncestorContainer;
22288 while (p.nodeType == 3) { // text node
22299 * Range intersection.. the hard stuff...
22303 * [ -- selected range --- ]
22307 * if end is before start or hits it. fail.
22308 * if start is after end or hits it fail.
22310 * if either hits (but other is outside. - then it's not
22316 // @see http://www.thismuchiknow.co.uk/?p=64.
22317 rangeIntersectsNode : function(range, node)
22319 var nodeRange = node.ownerDocument.createRange();
22321 nodeRange.selectNode(node);
22323 nodeRange.selectNodeContents(node);
22326 var rangeStartRange = range.cloneRange();
22327 rangeStartRange.collapse(true);
22329 var rangeEndRange = range.cloneRange();
22330 rangeEndRange.collapse(false);
22332 var nodeStartRange = nodeRange.cloneRange();
22333 nodeStartRange.collapse(true);
22335 var nodeEndRange = nodeRange.cloneRange();
22336 nodeEndRange.collapse(false);
22338 return rangeStartRange.compareBoundaryPoints(
22339 Range.START_TO_START, nodeEndRange) == -1 &&
22340 rangeEndRange.compareBoundaryPoints(
22341 Range.START_TO_START, nodeStartRange) == 1;
22345 rangeCompareNode : function(range, node)
22347 var nodeRange = node.ownerDocument.createRange();
22349 nodeRange.selectNode(node);
22351 nodeRange.selectNodeContents(node);
22355 range.collapse(true);
22357 nodeRange.collapse(true);
22359 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22360 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22362 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22364 var nodeIsBefore = ss == 1;
22365 var nodeIsAfter = ee == -1;
22367 if (nodeIsBefore && nodeIsAfter) {
22370 if (!nodeIsBefore && nodeIsAfter) {
22371 return 1; //right trailed.
22374 if (nodeIsBefore && !nodeIsAfter) {
22375 return 2; // left trailed.
22381 // private? - in a new class?
22382 cleanUpPaste : function()
22384 // cleans up the whole document..
22385 Roo.log('cleanuppaste');
22387 this.cleanUpChildren(this.doc.body);
22388 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22389 if (clean != this.doc.body.innerHTML) {
22390 this.doc.body.innerHTML = clean;
22395 cleanWordChars : function(input) {// change the chars to hex code
22396 var he = Roo.HtmlEditorCore;
22398 var output = input;
22399 Roo.each(he.swapCodes, function(sw) {
22400 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22402 output = output.replace(swapper, sw[1]);
22409 cleanUpChildren : function (n)
22411 if (!n.childNodes.length) {
22414 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22415 this.cleanUpChild(n.childNodes[i]);
22422 cleanUpChild : function (node)
22425 //console.log(node);
22426 if (node.nodeName == "#text") {
22427 // clean up silly Windows -- stuff?
22430 if (node.nodeName == "#comment") {
22431 node.parentNode.removeChild(node);
22432 // clean up silly Windows -- stuff?
22435 var lcname = node.tagName.toLowerCase();
22436 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22437 // whitelist of tags..
22439 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22441 node.parentNode.removeChild(node);
22446 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22448 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22449 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22451 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22452 // remove_keep_children = true;
22455 if (remove_keep_children) {
22456 this.cleanUpChildren(node);
22457 // inserts everything just before this node...
22458 while (node.childNodes.length) {
22459 var cn = node.childNodes[0];
22460 node.removeChild(cn);
22461 node.parentNode.insertBefore(cn, node);
22463 node.parentNode.removeChild(node);
22467 if (!node.attributes || !node.attributes.length) {
22468 this.cleanUpChildren(node);
22472 function cleanAttr(n,v)
22475 if (v.match(/^\./) || v.match(/^\//)) {
22478 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
22481 if (v.match(/^#/)) {
22484 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22485 node.removeAttribute(n);
22489 var cwhite = this.cwhite;
22490 var cblack = this.cblack;
22492 function cleanStyle(n,v)
22494 if (v.match(/expression/)) { //XSS?? should we even bother..
22495 node.removeAttribute(n);
22499 var parts = v.split(/;/);
22502 Roo.each(parts, function(p) {
22503 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22507 var l = p.split(':').shift().replace(/\s+/g,'');
22508 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22510 if ( cwhite.length && cblack.indexOf(l) > -1) {
22511 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22512 //node.removeAttribute(n);
22516 // only allow 'c whitelisted system attributes'
22517 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22518 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22519 //node.removeAttribute(n);
22529 if (clean.length) {
22530 node.setAttribute(n, clean.join(';'));
22532 node.removeAttribute(n);
22538 for (var i = node.attributes.length-1; i > -1 ; i--) {
22539 var a = node.attributes[i];
22542 if (a.name.toLowerCase().substr(0,2)=='on') {
22543 node.removeAttribute(a.name);
22546 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22547 node.removeAttribute(a.name);
22550 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22551 cleanAttr(a.name,a.value); // fixme..
22554 if (a.name == 'style') {
22555 cleanStyle(a.name,a.value);
22558 /// clean up MS crap..
22559 // tecnically this should be a list of valid class'es..
22562 if (a.name == 'class') {
22563 if (a.value.match(/^Mso/)) {
22564 node.className = '';
22567 if (a.value.match(/^body$/)) {
22568 node.className = '';
22579 this.cleanUpChildren(node);
22585 * Clean up MS wordisms...
22587 cleanWord : function(node)
22592 this.cleanWord(this.doc.body);
22595 if (node.nodeName == "#text") {
22596 // clean up silly Windows -- stuff?
22599 if (node.nodeName == "#comment") {
22600 node.parentNode.removeChild(node);
22601 // clean up silly Windows -- stuff?
22605 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22606 node.parentNode.removeChild(node);
22610 // remove - but keep children..
22611 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22612 while (node.childNodes.length) {
22613 var cn = node.childNodes[0];
22614 node.removeChild(cn);
22615 node.parentNode.insertBefore(cn, node);
22617 node.parentNode.removeChild(node);
22618 this.iterateChildren(node, this.cleanWord);
22622 if (node.className.length) {
22624 var cn = node.className.split(/\W+/);
22626 Roo.each(cn, function(cls) {
22627 if (cls.match(/Mso[a-zA-Z]+/)) {
22632 node.className = cna.length ? cna.join(' ') : '';
22634 node.removeAttribute("class");
22638 if (node.hasAttribute("lang")) {
22639 node.removeAttribute("lang");
22642 if (node.hasAttribute("style")) {
22644 var styles = node.getAttribute("style").split(";");
22646 Roo.each(styles, function(s) {
22647 if (!s.match(/:/)) {
22650 var kv = s.split(":");
22651 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22654 // what ever is left... we allow.
22657 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22658 if (!nstyle.length) {
22659 node.removeAttribute('style');
22662 this.iterateChildren(node, this.cleanWord);
22668 * iterateChildren of a Node, calling fn each time, using this as the scole..
22669 * @param {DomNode} node node to iterate children of.
22670 * @param {Function} fn method of this class to call on each item.
22672 iterateChildren : function(node, fn)
22674 if (!node.childNodes.length) {
22677 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22678 fn.call(this, node.childNodes[i])
22684 * cleanTableWidths.
22686 * Quite often pasting from word etc.. results in tables with column and widths.
22687 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22690 cleanTableWidths : function(node)
22695 this.cleanTableWidths(this.doc.body);
22700 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22703 Roo.log(node.tagName);
22704 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22705 this.iterateChildren(node, this.cleanTableWidths);
22708 if (node.hasAttribute('width')) {
22709 node.removeAttribute('width');
22713 if (node.hasAttribute("style")) {
22716 var styles = node.getAttribute("style").split(";");
22718 Roo.each(styles, function(s) {
22719 if (!s.match(/:/)) {
22722 var kv = s.split(":");
22723 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22726 // what ever is left... we allow.
22729 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22730 if (!nstyle.length) {
22731 node.removeAttribute('style');
22735 this.iterateChildren(node, this.cleanTableWidths);
22743 domToHTML : function(currentElement, depth, nopadtext) {
22745 depth = depth || 0;
22746 nopadtext = nopadtext || false;
22748 if (!currentElement) {
22749 return this.domToHTML(this.doc.body);
22752 //Roo.log(currentElement);
22754 var allText = false;
22755 var nodeName = currentElement.nodeName;
22756 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22758 if (nodeName == '#text') {
22760 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22765 if (nodeName != 'BODY') {
22768 // Prints the node tagName, such as <A>, <IMG>, etc
22771 for(i = 0; i < currentElement.attributes.length;i++) {
22773 var aname = currentElement.attributes.item(i).name;
22774 if (!currentElement.attributes.item(i).value.length) {
22777 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22780 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22789 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22792 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22797 // Traverse the tree
22799 var currentElementChild = currentElement.childNodes.item(i);
22800 var allText = true;
22801 var innerHTML = '';
22803 while (currentElementChild) {
22804 // Formatting code (indent the tree so it looks nice on the screen)
22805 var nopad = nopadtext;
22806 if (lastnode == 'SPAN') {
22810 if (currentElementChild.nodeName == '#text') {
22811 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22812 toadd = nopadtext ? toadd : toadd.trim();
22813 if (!nopad && toadd.length > 80) {
22814 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
22816 innerHTML += toadd;
22819 currentElementChild = currentElement.childNodes.item(i);
22825 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
22827 // Recursively traverse the tree structure of the child node
22828 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
22829 lastnode = currentElementChild.nodeName;
22831 currentElementChild=currentElement.childNodes.item(i);
22837 // The remaining code is mostly for formatting the tree
22838 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
22843 ret+= "</"+tagName+">";
22849 applyBlacklists : function()
22851 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
22852 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
22856 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22857 if (b.indexOf(tag) > -1) {
22860 this.white.push(tag);
22864 Roo.each(w, function(tag) {
22865 if (b.indexOf(tag) > -1) {
22868 if (this.white.indexOf(tag) > -1) {
22871 this.white.push(tag);
22876 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22877 if (w.indexOf(tag) > -1) {
22880 this.black.push(tag);
22884 Roo.each(b, function(tag) {
22885 if (w.indexOf(tag) > -1) {
22888 if (this.black.indexOf(tag) > -1) {
22891 this.black.push(tag);
22896 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
22897 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
22901 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22902 if (b.indexOf(tag) > -1) {
22905 this.cwhite.push(tag);
22909 Roo.each(w, function(tag) {
22910 if (b.indexOf(tag) > -1) {
22913 if (this.cwhite.indexOf(tag) > -1) {
22916 this.cwhite.push(tag);
22921 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22922 if (w.indexOf(tag) > -1) {
22925 this.cblack.push(tag);
22929 Roo.each(b, function(tag) {
22930 if (w.indexOf(tag) > -1) {
22933 if (this.cblack.indexOf(tag) > -1) {
22936 this.cblack.push(tag);
22941 setStylesheets : function(stylesheets)
22943 if(typeof(stylesheets) == 'string'){
22944 Roo.get(this.iframe.contentDocument.head).createChild({
22946 rel : 'stylesheet',
22955 Roo.each(stylesheets, function(s) {
22960 Roo.get(_this.iframe.contentDocument.head).createChild({
22962 rel : 'stylesheet',
22971 removeStylesheets : function()
22975 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
22980 setStyle : function(style)
22982 Roo.get(this.iframe.contentDocument.head).createChild({
22991 // hide stuff that is not compatible
23005 * @event specialkey
23009 * @cfg {String} fieldClass @hide
23012 * @cfg {String} focusClass @hide
23015 * @cfg {String} autoCreate @hide
23018 * @cfg {String} inputType @hide
23021 * @cfg {String} invalidClass @hide
23024 * @cfg {String} invalidText @hide
23027 * @cfg {String} msgFx @hide
23030 * @cfg {String} validateOnBlur @hide
23034 Roo.HtmlEditorCore.white = [
23035 'area', 'br', 'img', 'input', 'hr', 'wbr',
23037 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23038 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23039 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23040 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23041 'table', 'ul', 'xmp',
23043 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23046 'dir', 'menu', 'ol', 'ul', 'dl',
23052 Roo.HtmlEditorCore.black = [
23053 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23055 'base', 'basefont', 'bgsound', 'blink', 'body',
23056 'frame', 'frameset', 'head', 'html', 'ilayer',
23057 'iframe', 'layer', 'link', 'meta', 'object',
23058 'script', 'style' ,'title', 'xml' // clean later..
23060 Roo.HtmlEditorCore.clean = [
23061 'script', 'style', 'title', 'xml'
23063 Roo.HtmlEditorCore.remove = [
23068 Roo.HtmlEditorCore.ablack = [
23072 Roo.HtmlEditorCore.aclean = [
23073 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23077 Roo.HtmlEditorCore.pwhite= [
23078 'http', 'https', 'mailto'
23081 // white listed style attributes.
23082 Roo.HtmlEditorCore.cwhite= [
23083 // 'text-align', /// default is to allow most things..
23089 // black listed style attributes.
23090 Roo.HtmlEditorCore.cblack= [
23091 // 'font-size' -- this can be set by the project
23095 Roo.HtmlEditorCore.swapCodes =[
23114 * @class Roo.bootstrap.HtmlEditor
23115 * @extends Roo.bootstrap.TextArea
23116 * Bootstrap HtmlEditor class
23119 * Create a new HtmlEditor
23120 * @param {Object} config The config object
23123 Roo.bootstrap.HtmlEditor = function(config){
23124 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23125 if (!this.toolbars) {
23126 this.toolbars = [];
23129 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23132 * @event initialize
23133 * Fires when the editor is fully initialized (including the iframe)
23134 * @param {HtmlEditor} this
23139 * Fires when the editor is first receives the focus. Any insertion must wait
23140 * until after this event.
23141 * @param {HtmlEditor} this
23145 * @event beforesync
23146 * Fires before the textarea is updated with content from the editor iframe. Return false
23147 * to cancel the sync.
23148 * @param {HtmlEditor} this
23149 * @param {String} html
23153 * @event beforepush
23154 * Fires before the iframe editor is updated with content from the textarea. Return false
23155 * to cancel the push.
23156 * @param {HtmlEditor} this
23157 * @param {String} html
23162 * Fires when the textarea is updated with content from the editor iframe.
23163 * @param {HtmlEditor} this
23164 * @param {String} html
23169 * Fires when the iframe editor is updated with content from the textarea.
23170 * @param {HtmlEditor} this
23171 * @param {String} html
23175 * @event editmodechange
23176 * Fires when the editor switches edit modes
23177 * @param {HtmlEditor} this
23178 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23180 editmodechange: true,
23182 * @event editorevent
23183 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23184 * @param {HtmlEditor} this
23188 * @event firstfocus
23189 * Fires when on first focus - needed by toolbars..
23190 * @param {HtmlEditor} this
23195 * Auto save the htmlEditor value as a file into Events
23196 * @param {HtmlEditor} this
23200 * @event savedpreview
23201 * preview the saved version of htmlEditor
23202 * @param {HtmlEditor} this
23209 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23213 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23218 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23223 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23228 * @cfg {Number} height (in pixels)
23232 * @cfg {Number} width (in pixels)
23237 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23240 stylesheets: false,
23245 // private properties
23246 validationEvent : false,
23248 initialized : false,
23251 onFocus : Roo.emptyFn,
23253 hideMode:'offsets',
23255 tbContainer : false,
23259 toolbarContainer :function() {
23260 return this.wrap.select('.x-html-editor-tb',true).first();
23264 * Protected method that will not generally be called directly. It
23265 * is called when the editor creates its toolbar. Override this method if you need to
23266 * add custom toolbar buttons.
23267 * @param {HtmlEditor} editor
23269 createToolbar : function(){
23270 Roo.log('renewing');
23271 Roo.log("create toolbars");
23273 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23274 this.toolbars[0].render(this.toolbarContainer());
23278 // if (!editor.toolbars || !editor.toolbars.length) {
23279 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23282 // for (var i =0 ; i < editor.toolbars.length;i++) {
23283 // editor.toolbars[i] = Roo.factory(
23284 // typeof(editor.toolbars[i]) == 'string' ?
23285 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23286 // Roo.bootstrap.HtmlEditor);
23287 // editor.toolbars[i].init(editor);
23293 onRender : function(ct, position)
23295 // Roo.log("Call onRender: " + this.xtype);
23297 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23299 this.wrap = this.inputEl().wrap({
23300 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23303 this.editorcore.onRender(ct, position);
23305 if (this.resizable) {
23306 this.resizeEl = new Roo.Resizable(this.wrap, {
23310 minHeight : this.height,
23311 height: this.height,
23312 handles : this.resizable,
23315 resize : function(r, w, h) {
23316 _t.onResize(w,h); // -something
23322 this.createToolbar(this);
23325 if(!this.width && this.resizable){
23326 this.setSize(this.wrap.getSize());
23328 if (this.resizeEl) {
23329 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23330 // should trigger onReize..
23336 onResize : function(w, h)
23338 Roo.log('resize: ' +w + ',' + h );
23339 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23343 if(this.inputEl() ){
23344 if(typeof w == 'number'){
23345 var aw = w - this.wrap.getFrameWidth('lr');
23346 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23349 if(typeof h == 'number'){
23350 var tbh = -11; // fixme it needs to tool bar size!
23351 for (var i =0; i < this.toolbars.length;i++) {
23352 // fixme - ask toolbars for heights?
23353 tbh += this.toolbars[i].el.getHeight();
23354 //if (this.toolbars[i].footer) {
23355 // tbh += this.toolbars[i].footer.el.getHeight();
23363 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23364 ah -= 5; // knock a few pixes off for look..
23365 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23369 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23370 this.editorcore.onResize(ew,eh);
23375 * Toggles the editor between standard and source edit mode.
23376 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23378 toggleSourceEdit : function(sourceEditMode)
23380 this.editorcore.toggleSourceEdit(sourceEditMode);
23382 if(this.editorcore.sourceEditMode){
23383 Roo.log('editor - showing textarea');
23386 // Roo.log(this.syncValue());
23388 this.inputEl().removeClass(['hide', 'x-hidden']);
23389 this.inputEl().dom.removeAttribute('tabIndex');
23390 this.inputEl().focus();
23392 Roo.log('editor - hiding textarea');
23394 // Roo.log(this.pushValue());
23397 this.inputEl().addClass(['hide', 'x-hidden']);
23398 this.inputEl().dom.setAttribute('tabIndex', -1);
23399 //this.deferFocus();
23402 if(this.resizable){
23403 this.setSize(this.wrap.getSize());
23406 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23409 // private (for BoxComponent)
23410 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23412 // private (for BoxComponent)
23413 getResizeEl : function(){
23417 // private (for BoxComponent)
23418 getPositionEl : function(){
23423 initEvents : function(){
23424 this.originalValue = this.getValue();
23428 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23431 // markInvalid : Roo.emptyFn,
23433 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23436 // clearInvalid : Roo.emptyFn,
23438 setValue : function(v){
23439 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23440 this.editorcore.pushValue();
23445 deferFocus : function(){
23446 this.focus.defer(10, this);
23450 focus : function(){
23451 this.editorcore.focus();
23457 onDestroy : function(){
23463 for (var i =0; i < this.toolbars.length;i++) {
23464 // fixme - ask toolbars for heights?
23465 this.toolbars[i].onDestroy();
23468 this.wrap.dom.innerHTML = '';
23469 this.wrap.remove();
23474 onFirstFocus : function(){
23475 //Roo.log("onFirstFocus");
23476 this.editorcore.onFirstFocus();
23477 for (var i =0; i < this.toolbars.length;i++) {
23478 this.toolbars[i].onFirstFocus();
23484 syncValue : function()
23486 this.editorcore.syncValue();
23489 pushValue : function()
23491 this.editorcore.pushValue();
23495 // hide stuff that is not compatible
23509 * @event specialkey
23513 * @cfg {String} fieldClass @hide
23516 * @cfg {String} focusClass @hide
23519 * @cfg {String} autoCreate @hide
23522 * @cfg {String} inputType @hide
23525 * @cfg {String} invalidClass @hide
23528 * @cfg {String} invalidText @hide
23531 * @cfg {String} msgFx @hide
23534 * @cfg {String} validateOnBlur @hide
23543 Roo.namespace('Roo.bootstrap.htmleditor');
23545 * @class Roo.bootstrap.HtmlEditorToolbar1
23550 new Roo.bootstrap.HtmlEditor({
23553 new Roo.bootstrap.HtmlEditorToolbar1({
23554 disable : { fonts: 1 , format: 1, ..., ... , ...],
23560 * @cfg {Object} disable List of elements to disable..
23561 * @cfg {Array} btns List of additional buttons.
23565 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23568 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23571 Roo.apply(this, config);
23573 // default disabled, based on 'good practice'..
23574 this.disable = this.disable || {};
23575 Roo.applyIf(this.disable, {
23578 specialElements : true
23580 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23582 this.editor = config.editor;
23583 this.editorcore = config.editor.editorcore;
23585 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23587 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23588 // dont call parent... till later.
23590 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23595 editorcore : false,
23600 "h1","h2","h3","h4","h5","h6",
23602 "abbr", "acronym", "address", "cite", "samp", "var",
23606 onRender : function(ct, position)
23608 // Roo.log("Call onRender: " + this.xtype);
23610 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23612 this.el.dom.style.marginBottom = '0';
23614 var editorcore = this.editorcore;
23615 var editor= this.editor;
23618 var btn = function(id,cmd , toggle, handler, html){
23620 var event = toggle ? 'toggle' : 'click';
23625 xns: Roo.bootstrap,
23628 enableToggle:toggle !== false,
23630 pressed : toggle ? false : null,
23633 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23634 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23640 // var cb_box = function...
23645 xns: Roo.bootstrap,
23646 glyphicon : 'font',
23650 xns: Roo.bootstrap,
23654 Roo.each(this.formats, function(f) {
23655 style.menu.items.push({
23657 xns: Roo.bootstrap,
23658 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23663 editorcore.insertTag(this.tagname);
23670 children.push(style);
23672 btn('bold',false,true);
23673 btn('italic',false,true);
23674 btn('align-left', 'justifyleft',true);
23675 btn('align-center', 'justifycenter',true);
23676 btn('align-right' , 'justifyright',true);
23677 btn('link', false, false, function(btn) {
23678 //Roo.log("create link?");
23679 var url = prompt(this.createLinkText, this.defaultLinkValue);
23680 if(url && url != 'http:/'+'/'){
23681 this.editorcore.relayCmd('createlink', url);
23684 btn('list','insertunorderedlist',true);
23685 btn('pencil', false,true, function(btn){
23687 this.toggleSourceEdit(btn.pressed);
23690 if (this.editor.btns.length > 0) {
23691 for (var i = 0; i<this.editor.btns.length; i++) {
23692 children.push(this.editor.btns[i]);
23700 xns: Roo.bootstrap,
23705 xns: Roo.bootstrap,
23710 cog.menu.items.push({
23712 xns: Roo.bootstrap,
23713 html : Clean styles,
23718 editorcore.insertTag(this.tagname);
23727 this.xtype = 'NavSimplebar';
23729 for(var i=0;i< children.length;i++) {
23731 this.buttons.add(this.addxtypeChild(children[i]));
23735 editor.on('editorevent', this.updateToolbar, this);
23737 onBtnClick : function(id)
23739 this.editorcore.relayCmd(id);
23740 this.editorcore.focus();
23744 * Protected method that will not generally be called directly. It triggers
23745 * a toolbar update by reading the markup state of the current selection in the editor.
23747 updateToolbar: function(){
23749 if(!this.editorcore.activated){
23750 this.editor.onFirstFocus(); // is this neeed?
23754 var btns = this.buttons;
23755 var doc = this.editorcore.doc;
23756 btns.get('bold').setActive(doc.queryCommandState('bold'));
23757 btns.get('italic').setActive(doc.queryCommandState('italic'));
23758 //btns.get('underline').setActive(doc.queryCommandState('underline'));
23760 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23761 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23762 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23764 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23765 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23768 var ans = this.editorcore.getAllAncestors();
23769 if (this.formatCombo) {
23772 var store = this.formatCombo.store;
23773 this.formatCombo.setValue("");
23774 for (var i =0; i < ans.length;i++) {
23775 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23777 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23785 // hides menus... - so this cant be on a menu...
23786 Roo.bootstrap.MenuMgr.hideAll();
23788 Roo.bootstrap.MenuMgr.hideAll();
23789 //this.editorsyncValue();
23791 onFirstFocus: function() {
23792 this.buttons.each(function(item){
23796 toggleSourceEdit : function(sourceEditMode){
23799 if(sourceEditMode){
23800 Roo.log("disabling buttons");
23801 this.buttons.each( function(item){
23802 if(item.cmd != 'pencil'){
23808 Roo.log("enabling buttons");
23809 if(this.editorcore.initialized){
23810 this.buttons.each( function(item){
23816 Roo.log("calling toggole on editor");
23817 // tell the editor that it's been pressed..
23818 this.editor.toggleSourceEdit(sourceEditMode);
23828 * @class Roo.bootstrap.Table.AbstractSelectionModel
23829 * @extends Roo.util.Observable
23830 * Abstract base class for grid SelectionModels. It provides the interface that should be
23831 * implemented by descendant classes. This class should not be directly instantiated.
23834 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23835 this.locked = false;
23836 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23840 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
23841 /** @ignore Called by the grid automatically. Do not call directly. */
23842 init : function(grid){
23848 * Locks the selections.
23851 this.locked = true;
23855 * Unlocks the selections.
23857 unlock : function(){
23858 this.locked = false;
23862 * Returns true if the selections are locked.
23863 * @return {Boolean}
23865 isLocked : function(){
23866 return this.locked;
23870 * @extends Roo.bootstrap.Table.AbstractSelectionModel
23871 * @class Roo.bootstrap.Table.RowSelectionModel
23872 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23873 * It supports multiple selections and keyboard selection/navigation.
23875 * @param {Object} config
23878 Roo.bootstrap.Table.RowSelectionModel = function(config){
23879 Roo.apply(this, config);
23880 this.selections = new Roo.util.MixedCollection(false, function(o){
23885 this.lastActive = false;
23889 * @event selectionchange
23890 * Fires when the selection changes
23891 * @param {SelectionModel} this
23893 "selectionchange" : true,
23895 * @event afterselectionchange
23896 * Fires after the selection changes (eg. by key press or clicking)
23897 * @param {SelectionModel} this
23899 "afterselectionchange" : true,
23901 * @event beforerowselect
23902 * Fires when a row is selected being selected, return false to cancel.
23903 * @param {SelectionModel} this
23904 * @param {Number} rowIndex The selected index
23905 * @param {Boolean} keepExisting False if other selections will be cleared
23907 "beforerowselect" : true,
23910 * Fires when a row is selected.
23911 * @param {SelectionModel} this
23912 * @param {Number} rowIndex The selected index
23913 * @param {Roo.data.Record} r The record
23915 "rowselect" : true,
23917 * @event rowdeselect
23918 * Fires when a row is deselected.
23919 * @param {SelectionModel} this
23920 * @param {Number} rowIndex The selected index
23922 "rowdeselect" : true
23924 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23925 this.locked = false;
23928 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
23930 * @cfg {Boolean} singleSelect
23931 * True to allow selection of only one row at a time (defaults to false)
23933 singleSelect : false,
23936 initEvents : function()
23939 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23940 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
23941 //}else{ // allow click to work like normal
23942 // this.grid.on("rowclick", this.handleDragableRowClick, this);
23944 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23945 this.grid.on("rowclick", this.handleMouseDown, this);
23947 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23948 "up" : function(e){
23950 this.selectPrevious(e.shiftKey);
23951 }else if(this.last !== false && this.lastActive !== false){
23952 var last = this.last;
23953 this.selectRange(this.last, this.lastActive-1);
23954 this.grid.getView().focusRow(this.lastActive);
23955 if(last !== false){
23959 this.selectFirstRow();
23961 this.fireEvent("afterselectionchange", this);
23963 "down" : function(e){
23965 this.selectNext(e.shiftKey);
23966 }else if(this.last !== false && this.lastActive !== false){
23967 var last = this.last;
23968 this.selectRange(this.last, this.lastActive+1);
23969 this.grid.getView().focusRow(this.lastActive);
23970 if(last !== false){
23974 this.selectFirstRow();
23976 this.fireEvent("afterselectionchange", this);
23980 this.grid.store.on('load', function(){
23981 this.selections.clear();
23984 var view = this.grid.view;
23985 view.on("refresh", this.onRefresh, this);
23986 view.on("rowupdated", this.onRowUpdated, this);
23987 view.on("rowremoved", this.onRemove, this);
23992 onRefresh : function()
23994 var ds = this.grid.store, i, v = this.grid.view;
23995 var s = this.selections;
23996 s.each(function(r){
23997 if((i = ds.indexOfId(r.id)) != -1){
24006 onRemove : function(v, index, r){
24007 this.selections.remove(r);
24011 onRowUpdated : function(v, index, r){
24012 if(this.isSelected(r)){
24013 v.onRowSelect(index);
24019 * @param {Array} records The records to select
24020 * @param {Boolean} keepExisting (optional) True to keep existing selections
24022 selectRecords : function(records, keepExisting)
24025 this.clearSelections();
24027 var ds = this.grid.store;
24028 for(var i = 0, len = records.length; i < len; i++){
24029 this.selectRow(ds.indexOf(records[i]), true);
24034 * Gets the number of selected rows.
24037 getCount : function(){
24038 return this.selections.length;
24042 * Selects the first row in the grid.
24044 selectFirstRow : function(){
24049 * Select the last row.
24050 * @param {Boolean} keepExisting (optional) True to keep existing selections
24052 selectLastRow : function(keepExisting){
24053 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24054 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24058 * Selects the row immediately following the last selected row.
24059 * @param {Boolean} keepExisting (optional) True to keep existing selections
24061 selectNext : function(keepExisting)
24063 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24064 this.selectRow(this.last+1, keepExisting);
24065 this.grid.getView().focusRow(this.last);
24070 * Selects the row that precedes the last selected row.
24071 * @param {Boolean} keepExisting (optional) True to keep existing selections
24073 selectPrevious : function(keepExisting){
24075 this.selectRow(this.last-1, keepExisting);
24076 this.grid.getView().focusRow(this.last);
24081 * Returns the selected records
24082 * @return {Array} Array of selected records
24084 getSelections : function(){
24085 return [].concat(this.selections.items);
24089 * Returns the first selected record.
24092 getSelected : function(){
24093 return this.selections.itemAt(0);
24098 * Clears all selections.
24100 clearSelections : function(fast)
24106 var ds = this.grid.store;
24107 var s = this.selections;
24108 s.each(function(r){
24109 this.deselectRow(ds.indexOfId(r.id));
24113 this.selections.clear();
24120 * Selects all rows.
24122 selectAll : function(){
24126 this.selections.clear();
24127 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24128 this.selectRow(i, true);
24133 * Returns True if there is a selection.
24134 * @return {Boolean}
24136 hasSelection : function(){
24137 return this.selections.length > 0;
24141 * Returns True if the specified row is selected.
24142 * @param {Number/Record} record The record or index of the record to check
24143 * @return {Boolean}
24145 isSelected : function(index){
24146 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24147 return (r && this.selections.key(r.id) ? true : false);
24151 * Returns True if the specified record id is selected.
24152 * @param {String} id The id of record to check
24153 * @return {Boolean}
24155 isIdSelected : function(id){
24156 return (this.selections.key(id) ? true : false);
24161 handleMouseDBClick : function(e, t){
24165 handleMouseDown : function(e, t)
24167 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24168 if(this.isLocked() || rowIndex < 0 ){
24171 if(e.shiftKey && this.last !== false){
24172 var last = this.last;
24173 this.selectRange(last, rowIndex, e.ctrlKey);
24174 this.last = last; // reset the last
24178 var isSelected = this.isSelected(rowIndex);
24179 //Roo.log("select row:" + rowIndex);
24181 this.deselectRow(rowIndex);
24183 this.selectRow(rowIndex, true);
24187 if(e.button !== 0 && isSelected){
24188 alert('rowIndex 2: ' + rowIndex);
24189 view.focusRow(rowIndex);
24190 }else if(e.ctrlKey && isSelected){
24191 this.deselectRow(rowIndex);
24192 }else if(!isSelected){
24193 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24194 view.focusRow(rowIndex);
24198 this.fireEvent("afterselectionchange", this);
24201 handleDragableRowClick : function(grid, rowIndex, e)
24203 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24204 this.selectRow(rowIndex, false);
24205 grid.view.focusRow(rowIndex);
24206 this.fireEvent("afterselectionchange", this);
24211 * Selects multiple rows.
24212 * @param {Array} rows Array of the indexes of the row to select
24213 * @param {Boolean} keepExisting (optional) True to keep existing selections
24215 selectRows : function(rows, keepExisting){
24217 this.clearSelections();
24219 for(var i = 0, len = rows.length; i < len; i++){
24220 this.selectRow(rows[i], true);
24225 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24226 * @param {Number} startRow The index of the first row in the range
24227 * @param {Number} endRow The index of the last row in the range
24228 * @param {Boolean} keepExisting (optional) True to retain existing selections
24230 selectRange : function(startRow, endRow, keepExisting){
24235 this.clearSelections();
24237 if(startRow <= endRow){
24238 for(var i = startRow; i <= endRow; i++){
24239 this.selectRow(i, true);
24242 for(var i = startRow; i >= endRow; i--){
24243 this.selectRow(i, true);
24249 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24250 * @param {Number} startRow The index of the first row in the range
24251 * @param {Number} endRow The index of the last row in the range
24253 deselectRange : function(startRow, endRow, preventViewNotify){
24257 for(var i = startRow; i <= endRow; i++){
24258 this.deselectRow(i, preventViewNotify);
24264 * @param {Number} row The index of the row to select
24265 * @param {Boolean} keepExisting (optional) True to keep existing selections
24267 selectRow : function(index, keepExisting, preventViewNotify)
24269 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24272 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24273 if(!keepExisting || this.singleSelect){
24274 this.clearSelections();
24277 var r = this.grid.store.getAt(index);
24278 //console.log('selectRow - record id :' + r.id);
24280 this.selections.add(r);
24281 this.last = this.lastActive = index;
24282 if(!preventViewNotify){
24283 var proxy = new Roo.Element(
24284 this.grid.getRowDom(index)
24286 proxy.addClass('bg-info info');
24288 this.fireEvent("rowselect", this, index, r);
24289 this.fireEvent("selectionchange", this);
24295 * @param {Number} row The index of the row to deselect
24297 deselectRow : function(index, preventViewNotify)
24302 if(this.last == index){
24305 if(this.lastActive == index){
24306 this.lastActive = false;
24309 var r = this.grid.store.getAt(index);
24314 this.selections.remove(r);
24315 //.console.log('deselectRow - record id :' + r.id);
24316 if(!preventViewNotify){
24318 var proxy = new Roo.Element(
24319 this.grid.getRowDom(index)
24321 proxy.removeClass('bg-info info');
24323 this.fireEvent("rowdeselect", this, index);
24324 this.fireEvent("selectionchange", this);
24328 restoreLast : function(){
24330 this.last = this._last;
24335 acceptsNav : function(row, col, cm){
24336 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24340 onEditorKey : function(field, e){
24341 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24346 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24348 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24350 }else if(k == e.ENTER && !e.ctrlKey){
24354 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24356 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24358 }else if(k == e.ESC){
24362 g.startEditing(newCell[0], newCell[1]);
24368 * Ext JS Library 1.1.1
24369 * Copyright(c) 2006-2007, Ext JS, LLC.
24371 * Originally Released Under LGPL - original licence link has changed is not relivant.
24374 * <script type="text/javascript">
24378 * @class Roo.bootstrap.PagingToolbar
24379 * @extends Roo.bootstrap.NavSimplebar
24380 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24382 * Create a new PagingToolbar
24383 * @param {Object} config The config object
24384 * @param {Roo.data.Store} store
24386 Roo.bootstrap.PagingToolbar = function(config)
24388 // old args format still supported... - xtype is prefered..
24389 // created from xtype...
24391 this.ds = config.dataSource;
24393 if (config.store && !this.ds) {
24394 this.store= Roo.factory(config.store, Roo.data);
24395 this.ds = this.store;
24396 this.ds.xmodule = this.xmodule || false;
24399 this.toolbarItems = [];
24400 if (config.items) {
24401 this.toolbarItems = config.items;
24404 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24409 this.bind(this.ds);
24412 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24416 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24418 * @cfg {Roo.data.Store} dataSource
24419 * The underlying data store providing the paged data
24422 * @cfg {String/HTMLElement/Element} container
24423 * container The id or element that will contain the toolbar
24426 * @cfg {Boolean} displayInfo
24427 * True to display the displayMsg (defaults to false)
24430 * @cfg {Number} pageSize
24431 * The number of records to display per page (defaults to 20)
24435 * @cfg {String} displayMsg
24436 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24438 displayMsg : 'Displaying {0} - {1} of {2}',
24440 * @cfg {String} emptyMsg
24441 * The message to display when no records are found (defaults to "No data to display")
24443 emptyMsg : 'No data to display',
24445 * Customizable piece of the default paging text (defaults to "Page")
24448 beforePageText : "Page",
24450 * Customizable piece of the default paging text (defaults to "of %0")
24453 afterPageText : "of {0}",
24455 * Customizable piece of the default paging text (defaults to "First Page")
24458 firstText : "First Page",
24460 * Customizable piece of the default paging text (defaults to "Previous Page")
24463 prevText : "Previous Page",
24465 * Customizable piece of the default paging text (defaults to "Next Page")
24468 nextText : "Next Page",
24470 * Customizable piece of the default paging text (defaults to "Last Page")
24473 lastText : "Last Page",
24475 * Customizable piece of the default paging text (defaults to "Refresh")
24478 refreshText : "Refresh",
24482 onRender : function(ct, position)
24484 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24485 this.navgroup.parentId = this.id;
24486 this.navgroup.onRender(this.el, null);
24487 // add the buttons to the navgroup
24489 if(this.displayInfo){
24490 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24491 this.displayEl = this.el.select('.x-paging-info', true).first();
24492 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24493 // this.displayEl = navel.el.select('span',true).first();
24499 Roo.each(_this.buttons, function(e){ // this might need to use render????
24500 Roo.factory(e).onRender(_this.el, null);
24504 Roo.each(_this.toolbarItems, function(e) {
24505 _this.navgroup.addItem(e);
24509 this.first = this.navgroup.addItem({
24510 tooltip: this.firstText,
24512 icon : 'fa fa-backward',
24514 preventDefault: true,
24515 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24518 this.prev = this.navgroup.addItem({
24519 tooltip: this.prevText,
24521 icon : 'fa fa-step-backward',
24523 preventDefault: true,
24524 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24526 //this.addSeparator();
24529 var field = this.navgroup.addItem( {
24531 cls : 'x-paging-position',
24533 html : this.beforePageText +
24534 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24535 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24538 this.field = field.el.select('input', true).first();
24539 this.field.on("keydown", this.onPagingKeydown, this);
24540 this.field.on("focus", function(){this.dom.select();});
24543 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24544 //this.field.setHeight(18);
24545 //this.addSeparator();
24546 this.next = this.navgroup.addItem({
24547 tooltip: this.nextText,
24549 html : ' <i class="fa fa-step-forward">',
24551 preventDefault: true,
24552 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24554 this.last = this.navgroup.addItem({
24555 tooltip: this.lastText,
24556 icon : 'fa fa-forward',
24559 preventDefault: true,
24560 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24562 //this.addSeparator();
24563 this.loading = this.navgroup.addItem({
24564 tooltip: this.refreshText,
24565 icon: 'fa fa-refresh',
24566 preventDefault: true,
24567 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24573 updateInfo : function(){
24574 if(this.displayEl){
24575 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24576 var msg = count == 0 ?
24580 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24582 this.displayEl.update(msg);
24587 onLoad : function(ds, r, o)
24589 this.cursor = o.params.start ? o.params.start : 0;
24591 var d = this.getPageData(),
24596 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24597 this.field.dom.value = ap;
24598 this.first.setDisabled(ap == 1);
24599 this.prev.setDisabled(ap == 1);
24600 this.next.setDisabled(ap == ps);
24601 this.last.setDisabled(ap == ps);
24602 this.loading.enable();
24607 getPageData : function(){
24608 var total = this.ds.getTotalCount();
24611 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24612 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24617 onLoadError : function(){
24618 this.loading.enable();
24622 onPagingKeydown : function(e){
24623 var k = e.getKey();
24624 var d = this.getPageData();
24626 var v = this.field.dom.value, pageNum;
24627 if(!v || isNaN(pageNum = parseInt(v, 10))){
24628 this.field.dom.value = d.activePage;
24631 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24632 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24635 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))
24637 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24638 this.field.dom.value = pageNum;
24639 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24642 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24644 var v = this.field.dom.value, pageNum;
24645 var increment = (e.shiftKey) ? 10 : 1;
24646 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24649 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24650 this.field.dom.value = d.activePage;
24653 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24655 this.field.dom.value = parseInt(v, 10) + increment;
24656 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24657 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24664 beforeLoad : function(){
24666 this.loading.disable();
24671 onClick : function(which){
24680 ds.load({params:{start: 0, limit: this.pageSize}});
24683 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24686 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24689 var total = ds.getTotalCount();
24690 var extra = total % this.pageSize;
24691 var lastStart = extra ? (total - extra) : total-this.pageSize;
24692 ds.load({params:{start: lastStart, limit: this.pageSize}});
24695 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24701 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24702 * @param {Roo.data.Store} store The data store to unbind
24704 unbind : function(ds){
24705 ds.un("beforeload", this.beforeLoad, this);
24706 ds.un("load", this.onLoad, this);
24707 ds.un("loadexception", this.onLoadError, this);
24708 ds.un("remove", this.updateInfo, this);
24709 ds.un("add", this.updateInfo, this);
24710 this.ds = undefined;
24714 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24715 * @param {Roo.data.Store} store The data store to bind
24717 bind : function(ds){
24718 ds.on("beforeload", this.beforeLoad, this);
24719 ds.on("load", this.onLoad, this);
24720 ds.on("loadexception", this.onLoadError, this);
24721 ds.on("remove", this.updateInfo, this);
24722 ds.on("add", this.updateInfo, this);
24733 * @class Roo.bootstrap.MessageBar
24734 * @extends Roo.bootstrap.Component
24735 * Bootstrap MessageBar class
24736 * @cfg {String} html contents of the MessageBar
24737 * @cfg {String} weight (info | success | warning | danger) default info
24738 * @cfg {String} beforeClass insert the bar before the given class
24739 * @cfg {Boolean} closable (true | false) default false
24740 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24743 * Create a new Element
24744 * @param {Object} config The config object
24747 Roo.bootstrap.MessageBar = function(config){
24748 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24751 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
24757 beforeClass: 'bootstrap-sticky-wrap',
24759 getAutoCreate : function(){
24763 cls: 'alert alert-dismissable alert-' + this.weight,
24768 html: this.html || ''
24774 cfg.cls += ' alert-messages-fixed';
24788 onRender : function(ct, position)
24790 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24793 var cfg = Roo.apply({}, this.getAutoCreate());
24797 cfg.cls += ' ' + this.cls;
24800 cfg.style = this.style;
24802 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24804 this.el.setVisibilityMode(Roo.Element.DISPLAY);
24807 this.el.select('>button.close').on('click', this.hide, this);
24813 if (!this.rendered) {
24819 this.fireEvent('show', this);
24825 if (!this.rendered) {
24831 this.fireEvent('hide', this);
24834 update : function()
24836 // var e = this.el.dom.firstChild;
24838 // if(this.closable){
24839 // e = e.nextSibling;
24842 // e.data = this.html || '';
24844 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24860 * @class Roo.bootstrap.Graph
24861 * @extends Roo.bootstrap.Component
24862 * Bootstrap Graph class
24866 @cfg {String} graphtype bar | vbar | pie
24867 @cfg {number} g_x coodinator | centre x (pie)
24868 @cfg {number} g_y coodinator | centre y (pie)
24869 @cfg {number} g_r radius (pie)
24870 @cfg {number} g_height height of the chart (respected by all elements in the set)
24871 @cfg {number} g_width width of the chart (respected by all elements in the set)
24872 @cfg {Object} title The title of the chart
24875 -opts (object) options for the chart
24877 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24878 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24880 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.
24881 o stacked (boolean) whether or not to tread values as in a stacked bar chart
24883 o stretch (boolean)
24885 -opts (object) options for the pie
24888 o startAngle (number)
24889 o endAngle (number)
24893 * Create a new Input
24894 * @param {Object} config The config object
24897 Roo.bootstrap.Graph = function(config){
24898 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24904 * The img click event for the img.
24905 * @param {Roo.EventObject} e
24911 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
24922 //g_colors: this.colors,
24929 getAutoCreate : function(){
24940 onRender : function(ct,position){
24943 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24945 if (typeof(Raphael) == 'undefined') {
24946 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24950 this.raphael = Raphael(this.el.dom);
24952 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24953 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24954 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24955 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24957 r.text(160, 10, "Single Series Chart").attr(txtattr);
24958 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24959 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24960 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24962 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24963 r.barchart(330, 10, 300, 220, data1);
24964 r.barchart(10, 250, 300, 220, data2, {stacked: true});
24965 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
24968 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24969 // r.barchart(30, 30, 560, 250, xdata, {
24970 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
24971 // axis : "0 0 1 1",
24972 // axisxlabels : xdata
24973 // //yvalues : cols,
24976 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
24978 // this.load(null,xdata,{
24979 // axis : "0 0 1 1",
24980 // axisxlabels : xdata
24985 load : function(graphtype,xdata,opts)
24987 this.raphael.clear();
24989 graphtype = this.graphtype;
24994 var r = this.raphael,
24995 fin = function () {
24996 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
24998 fout = function () {
24999 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25001 pfin = function() {
25002 this.sector.stop();
25003 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25006 this.label[0].stop();
25007 this.label[0].attr({ r: 7.5 });
25008 this.label[1].attr({ "font-weight": 800 });
25011 pfout = function() {
25012 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25015 this.label[0].animate({ r: 5 }, 500, "bounce");
25016 this.label[1].attr({ "font-weight": 400 });
25022 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25025 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25028 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25029 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25031 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25038 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25043 setTitle: function(o)
25048 initEvents: function() {
25051 this.el.on('click', this.onClick, this);
25055 onClick : function(e)
25057 Roo.log('img onclick');
25058 this.fireEvent('click', this, e);
25070 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25073 * @class Roo.bootstrap.dash.NumberBox
25074 * @extends Roo.bootstrap.Component
25075 * Bootstrap NumberBox class
25076 * @cfg {String} headline Box headline
25077 * @cfg {String} content Box content
25078 * @cfg {String} icon Box icon
25079 * @cfg {String} footer Footer text
25080 * @cfg {String} fhref Footer href
25083 * Create a new NumberBox
25084 * @param {Object} config The config object
25088 Roo.bootstrap.dash.NumberBox = function(config){
25089 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25093 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25102 getAutoCreate : function(){
25106 cls : 'small-box ',
25114 cls : 'roo-headline',
25115 html : this.headline
25119 cls : 'roo-content',
25120 html : this.content
25134 cls : 'ion ' + this.icon
25143 cls : 'small-box-footer',
25144 href : this.fhref || '#',
25148 cfg.cn.push(footer);
25155 onRender : function(ct,position){
25156 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25163 setHeadline: function (value)
25165 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25168 setFooter: function (value, href)
25170 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25173 this.el.select('a.small-box-footer',true).first().attr('href', href);
25178 setContent: function (value)
25180 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25183 initEvents: function()
25197 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25200 * @class Roo.bootstrap.dash.TabBox
25201 * @extends Roo.bootstrap.Component
25202 * Bootstrap TabBox class
25203 * @cfg {String} title Title of the TabBox
25204 * @cfg {String} icon Icon of the TabBox
25205 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25206 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25209 * Create a new TabBox
25210 * @param {Object} config The config object
25214 Roo.bootstrap.dash.TabBox = function(config){
25215 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25220 * When a pane is added
25221 * @param {Roo.bootstrap.dash.TabPane} pane
25225 * @event activatepane
25226 * When a pane is activated
25227 * @param {Roo.bootstrap.dash.TabPane} pane
25229 "activatepane" : true
25237 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25242 tabScrollable : false,
25244 getChildContainer : function()
25246 return this.el.select('.tab-content', true).first();
25249 getAutoCreate : function(){
25253 cls: 'pull-left header',
25261 cls: 'fa ' + this.icon
25267 cls: 'nav nav-tabs pull-right',
25273 if(this.tabScrollable){
25280 cls: 'nav nav-tabs pull-right',
25291 cls: 'nav-tabs-custom',
25296 cls: 'tab-content no-padding',
25304 initEvents : function()
25306 //Roo.log('add add pane handler');
25307 this.on('addpane', this.onAddPane, this);
25310 * Updates the box title
25311 * @param {String} html to set the title to.
25313 setTitle : function(value)
25315 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25317 onAddPane : function(pane)
25319 this.panes.push(pane);
25320 //Roo.log('addpane');
25322 // tabs are rendere left to right..
25323 if(!this.showtabs){
25327 var ctr = this.el.select('.nav-tabs', true).first();
25330 var existing = ctr.select('.nav-tab',true);
25331 var qty = existing.getCount();;
25334 var tab = ctr.createChild({
25336 cls : 'nav-tab' + (qty ? '' : ' active'),
25344 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25347 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25349 pane.el.addClass('active');
25354 onTabClick : function(ev,un,ob,pane)
25356 //Roo.log('tab - prev default');
25357 ev.preventDefault();
25360 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25361 pane.tab.addClass('active');
25362 //Roo.log(pane.title);
25363 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25364 // technically we should have a deactivate event.. but maybe add later.
25365 // and it should not de-activate the selected tab...
25366 this.fireEvent('activatepane', pane);
25367 pane.el.addClass('active');
25368 pane.fireEvent('activate');
25373 getActivePane : function()
25376 Roo.each(this.panes, function(p) {
25377 if(p.el.hasClass('active')){
25398 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25400 * @class Roo.bootstrap.TabPane
25401 * @extends Roo.bootstrap.Component
25402 * Bootstrap TabPane class
25403 * @cfg {Boolean} active (false | true) Default false
25404 * @cfg {String} title title of panel
25408 * Create a new TabPane
25409 * @param {Object} config The config object
25412 Roo.bootstrap.dash.TabPane = function(config){
25413 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25419 * When a pane is activated
25420 * @param {Roo.bootstrap.dash.TabPane} pane
25427 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25432 // the tabBox that this is attached to.
25435 getAutoCreate : function()
25443 cfg.cls += ' active';
25448 initEvents : function()
25450 //Roo.log('trigger add pane handler');
25451 this.parent().fireEvent('addpane', this)
25455 * Updates the tab title
25456 * @param {String} html to set the title to.
25458 setTitle: function(str)
25464 this.tab.select('a', true).first().dom.innerHTML = str;
25481 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25484 * @class Roo.bootstrap.menu.Menu
25485 * @extends Roo.bootstrap.Component
25486 * Bootstrap Menu class - container for Menu
25487 * @cfg {String} html Text of the menu
25488 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25489 * @cfg {String} icon Font awesome icon
25490 * @cfg {String} pos Menu align to (top | bottom) default bottom
25494 * Create a new Menu
25495 * @param {Object} config The config object
25499 Roo.bootstrap.menu.Menu = function(config){
25500 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25504 * @event beforeshow
25505 * Fires before this menu is displayed
25506 * @param {Roo.bootstrap.menu.Menu} this
25510 * @event beforehide
25511 * Fires before this menu is hidden
25512 * @param {Roo.bootstrap.menu.Menu} this
25517 * Fires after this menu is displayed
25518 * @param {Roo.bootstrap.menu.Menu} this
25523 * Fires after this menu is hidden
25524 * @param {Roo.bootstrap.menu.Menu} this
25529 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25530 * @param {Roo.bootstrap.menu.Menu} this
25531 * @param {Roo.EventObject} e
25538 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25542 weight : 'default',
25547 getChildContainer : function() {
25548 if(this.isSubMenu){
25552 return this.el.select('ul.dropdown-menu', true).first();
25555 getAutoCreate : function()
25560 cls : 'roo-menu-text',
25568 cls : 'fa ' + this.icon
25579 cls : 'dropdown-button btn btn-' + this.weight,
25584 cls : 'dropdown-toggle btn btn-' + this.weight,
25594 cls : 'dropdown-menu'
25600 if(this.pos == 'top'){
25601 cfg.cls += ' dropup';
25604 if(this.isSubMenu){
25607 cls : 'dropdown-menu'
25614 onRender : function(ct, position)
25616 this.isSubMenu = ct.hasClass('dropdown-submenu');
25618 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25621 initEvents : function()
25623 if(this.isSubMenu){
25627 this.hidden = true;
25629 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25630 this.triggerEl.on('click', this.onTriggerPress, this);
25632 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25633 this.buttonEl.on('click', this.onClick, this);
25639 if(this.isSubMenu){
25643 return this.el.select('ul.dropdown-menu', true).first();
25646 onClick : function(e)
25648 this.fireEvent("click", this, e);
25651 onTriggerPress : function(e)
25653 if (this.isVisible()) {
25660 isVisible : function(){
25661 return !this.hidden;
25666 this.fireEvent("beforeshow", this);
25668 this.hidden = false;
25669 this.el.addClass('open');
25671 Roo.get(document).on("mouseup", this.onMouseUp, this);
25673 this.fireEvent("show", this);
25680 this.fireEvent("beforehide", this);
25682 this.hidden = true;
25683 this.el.removeClass('open');
25685 Roo.get(document).un("mouseup", this.onMouseUp);
25687 this.fireEvent("hide", this);
25690 onMouseUp : function()
25704 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25707 * @class Roo.bootstrap.menu.Item
25708 * @extends Roo.bootstrap.Component
25709 * Bootstrap MenuItem class
25710 * @cfg {Boolean} submenu (true | false) default false
25711 * @cfg {String} html text of the item
25712 * @cfg {String} href the link
25713 * @cfg {Boolean} disable (true | false) default false
25714 * @cfg {Boolean} preventDefault (true | false) default true
25715 * @cfg {String} icon Font awesome icon
25716 * @cfg {String} pos Submenu align to (left | right) default right
25720 * Create a new Item
25721 * @param {Object} config The config object
25725 Roo.bootstrap.menu.Item = function(config){
25726 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25730 * Fires when the mouse is hovering over this menu
25731 * @param {Roo.bootstrap.menu.Item} this
25732 * @param {Roo.EventObject} e
25737 * Fires when the mouse exits this menu
25738 * @param {Roo.bootstrap.menu.Item} this
25739 * @param {Roo.EventObject} e
25745 * The raw click event for the entire grid.
25746 * @param {Roo.EventObject} e
25752 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
25757 preventDefault: true,
25762 getAutoCreate : function()
25767 cls : 'roo-menu-item-text',
25775 cls : 'fa ' + this.icon
25784 href : this.href || '#',
25791 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25795 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25797 if(this.pos == 'left'){
25798 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25805 initEvents : function()
25807 this.el.on('mouseover', this.onMouseOver, this);
25808 this.el.on('mouseout', this.onMouseOut, this);
25810 this.el.select('a', true).first().on('click', this.onClick, this);
25814 onClick : function(e)
25816 if(this.preventDefault){
25817 e.preventDefault();
25820 this.fireEvent("click", this, e);
25823 onMouseOver : function(e)
25825 if(this.submenu && this.pos == 'left'){
25826 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25829 this.fireEvent("mouseover", this, e);
25832 onMouseOut : function(e)
25834 this.fireEvent("mouseout", this, e);
25846 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25849 * @class Roo.bootstrap.menu.Separator
25850 * @extends Roo.bootstrap.Component
25851 * Bootstrap Separator class
25854 * Create a new Separator
25855 * @param {Object} config The config object
25859 Roo.bootstrap.menu.Separator = function(config){
25860 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25863 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
25865 getAutoCreate : function(){
25886 * @class Roo.bootstrap.Tooltip
25887 * Bootstrap Tooltip class
25888 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25889 * to determine which dom element triggers the tooltip.
25891 * It needs to add support for additional attributes like tooltip-position
25894 * Create a new Toolti
25895 * @param {Object} config The config object
25898 Roo.bootstrap.Tooltip = function(config){
25899 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25901 this.alignment = Roo.bootstrap.Tooltip.alignment;
25903 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25904 this.alignment = config.alignment;
25909 Roo.apply(Roo.bootstrap.Tooltip, {
25911 * @function init initialize tooltip monitoring.
25915 currentTip : false,
25916 currentRegion : false,
25922 Roo.get(document).on('mouseover', this.enter ,this);
25923 Roo.get(document).on('mouseout', this.leave, this);
25926 this.currentTip = new Roo.bootstrap.Tooltip();
25929 enter : function(ev)
25931 var dom = ev.getTarget();
25933 //Roo.log(['enter',dom]);
25934 var el = Roo.fly(dom);
25935 if (this.currentEl) {
25937 //Roo.log(this.currentEl);
25938 //Roo.log(this.currentEl.contains(dom));
25939 if (this.currentEl == el) {
25942 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25948 if (this.currentTip.el) {
25949 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25953 if(!el || el.dom == document){
25959 // you can not look for children, as if el is the body.. then everythign is the child..
25960 if (!el.attr('tooltip')) { //
25961 if (!el.select("[tooltip]").elements.length) {
25964 // is the mouse over this child...?
25965 bindEl = el.select("[tooltip]").first();
25966 var xy = ev.getXY();
25967 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
25968 //Roo.log("not in region.");
25971 //Roo.log("child element over..");
25974 this.currentEl = bindEl;
25975 this.currentTip.bind(bindEl);
25976 this.currentRegion = Roo.lib.Region.getRegion(dom);
25977 this.currentTip.enter();
25980 leave : function(ev)
25982 var dom = ev.getTarget();
25983 //Roo.log(['leave',dom]);
25984 if (!this.currentEl) {
25989 if (dom != this.currentEl.dom) {
25992 var xy = ev.getXY();
25993 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
25996 // only activate leave if mouse cursor is outside... bounding box..
26001 if (this.currentTip) {
26002 this.currentTip.leave();
26004 //Roo.log('clear currentEl');
26005 this.currentEl = false;
26010 'left' : ['r-l', [-2,0], 'right'],
26011 'right' : ['l-r', [2,0], 'left'],
26012 'bottom' : ['t-b', [0,2], 'top'],
26013 'top' : [ 'b-t', [0,-2], 'bottom']
26019 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26024 delay : null, // can be { show : 300 , hide: 500}
26028 hoverState : null, //???
26030 placement : 'bottom',
26034 getAutoCreate : function(){
26041 cls : 'tooltip-arrow'
26044 cls : 'tooltip-inner'
26051 bind : function(el)
26057 enter : function () {
26059 if (this.timeout != null) {
26060 clearTimeout(this.timeout);
26063 this.hoverState = 'in';
26064 //Roo.log("enter - show");
26065 if (!this.delay || !this.delay.show) {
26070 this.timeout = setTimeout(function () {
26071 if (_t.hoverState == 'in') {
26074 }, this.delay.show);
26078 clearTimeout(this.timeout);
26080 this.hoverState = 'out';
26081 if (!this.delay || !this.delay.hide) {
26087 this.timeout = setTimeout(function () {
26088 //Roo.log("leave - timeout");
26090 if (_t.hoverState == 'out') {
26092 Roo.bootstrap.Tooltip.currentEl = false;
26097 show : function (msg)
26100 this.render(document.body);
26103 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26105 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26107 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26109 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26111 var placement = typeof this.placement == 'function' ?
26112 this.placement.call(this, this.el, on_el) :
26115 var autoToken = /\s?auto?\s?/i;
26116 var autoPlace = autoToken.test(placement);
26118 placement = placement.replace(autoToken, '') || 'top';
26122 //this.el.setXY([0,0]);
26124 //this.el.dom.style.display='block';
26126 //this.el.appendTo(on_el);
26128 var p = this.getPosition();
26129 var box = this.el.getBox();
26135 var align = this.alignment[placement];
26137 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26139 if(placement == 'top' || placement == 'bottom'){
26141 placement = 'right';
26144 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26145 placement = 'left';
26148 var scroll = Roo.select('body', true).first().getScroll();
26150 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26156 this.el.alignTo(this.bindEl, align[0],align[1]);
26157 //var arrow = this.el.select('.arrow',true).first();
26158 //arrow.set(align[2],
26160 this.el.addClass(placement);
26162 this.el.addClass('in fade');
26164 this.hoverState = null;
26166 if (this.el.hasClass('fade')) {
26177 //this.el.setXY([0,0]);
26178 this.el.removeClass('in');
26194 * @class Roo.bootstrap.LocationPicker
26195 * @extends Roo.bootstrap.Component
26196 * Bootstrap LocationPicker class
26197 * @cfg {Number} latitude Position when init default 0
26198 * @cfg {Number} longitude Position when init default 0
26199 * @cfg {Number} zoom default 15
26200 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26201 * @cfg {Boolean} mapTypeControl default false
26202 * @cfg {Boolean} disableDoubleClickZoom default false
26203 * @cfg {Boolean} scrollwheel default true
26204 * @cfg {Boolean} streetViewControl default false
26205 * @cfg {Number} radius default 0
26206 * @cfg {String} locationName
26207 * @cfg {Boolean} draggable default true
26208 * @cfg {Boolean} enableAutocomplete default false
26209 * @cfg {Boolean} enableReverseGeocode default true
26210 * @cfg {String} markerTitle
26213 * Create a new LocationPicker
26214 * @param {Object} config The config object
26218 Roo.bootstrap.LocationPicker = function(config){
26220 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26225 * Fires when the picker initialized.
26226 * @param {Roo.bootstrap.LocationPicker} this
26227 * @param {Google Location} location
26231 * @event positionchanged
26232 * Fires when the picker position changed.
26233 * @param {Roo.bootstrap.LocationPicker} this
26234 * @param {Google Location} location
26236 positionchanged : true,
26239 * Fires when the map resize.
26240 * @param {Roo.bootstrap.LocationPicker} this
26245 * Fires when the map show.
26246 * @param {Roo.bootstrap.LocationPicker} this
26251 * Fires when the map hide.
26252 * @param {Roo.bootstrap.LocationPicker} this
26257 * Fires when click the map.
26258 * @param {Roo.bootstrap.LocationPicker} this
26259 * @param {Map event} e
26263 * @event mapRightClick
26264 * Fires when right click the map.
26265 * @param {Roo.bootstrap.LocationPicker} this
26266 * @param {Map event} e
26268 mapRightClick : true,
26270 * @event markerClick
26271 * Fires when click the marker.
26272 * @param {Roo.bootstrap.LocationPicker} this
26273 * @param {Map event} e
26275 markerClick : true,
26277 * @event markerRightClick
26278 * Fires when right click the marker.
26279 * @param {Roo.bootstrap.LocationPicker} this
26280 * @param {Map event} e
26282 markerRightClick : true,
26284 * @event OverlayViewDraw
26285 * Fires when OverlayView Draw
26286 * @param {Roo.bootstrap.LocationPicker} this
26288 OverlayViewDraw : true,
26290 * @event OverlayViewOnAdd
26291 * Fires when OverlayView Draw
26292 * @param {Roo.bootstrap.LocationPicker} this
26294 OverlayViewOnAdd : true,
26296 * @event OverlayViewOnRemove
26297 * Fires when OverlayView Draw
26298 * @param {Roo.bootstrap.LocationPicker} this
26300 OverlayViewOnRemove : true,
26302 * @event OverlayViewShow
26303 * Fires when OverlayView Draw
26304 * @param {Roo.bootstrap.LocationPicker} this
26305 * @param {Pixel} cpx
26307 OverlayViewShow : true,
26309 * @event OverlayViewHide
26310 * Fires when OverlayView Draw
26311 * @param {Roo.bootstrap.LocationPicker} this
26313 OverlayViewHide : true,
26315 * @event loadexception
26316 * Fires when load google lib failed.
26317 * @param {Roo.bootstrap.LocationPicker} this
26319 loadexception : true
26324 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26326 gMapContext: false,
26332 mapTypeControl: false,
26333 disableDoubleClickZoom: false,
26335 streetViewControl: false,
26339 enableAutocomplete: false,
26340 enableReverseGeocode: true,
26343 getAutoCreate: function()
26348 cls: 'roo-location-picker'
26354 initEvents: function(ct, position)
26356 if(!this.el.getWidth() || this.isApplied()){
26360 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26365 initial: function()
26367 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26368 this.fireEvent('loadexception', this);
26372 if(!this.mapTypeId){
26373 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26376 this.gMapContext = this.GMapContext();
26378 this.initOverlayView();
26380 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26384 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26385 _this.setPosition(_this.gMapContext.marker.position);
26388 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26389 _this.fireEvent('mapClick', this, event);
26393 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26394 _this.fireEvent('mapRightClick', this, event);
26398 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26399 _this.fireEvent('markerClick', this, event);
26403 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26404 _this.fireEvent('markerRightClick', this, event);
26408 this.setPosition(this.gMapContext.location);
26410 this.fireEvent('initial', this, this.gMapContext.location);
26413 initOverlayView: function()
26417 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26421 _this.fireEvent('OverlayViewDraw', _this);
26426 _this.fireEvent('OverlayViewOnAdd', _this);
26429 onRemove: function()
26431 _this.fireEvent('OverlayViewOnRemove', _this);
26434 show: function(cpx)
26436 _this.fireEvent('OverlayViewShow', _this, cpx);
26441 _this.fireEvent('OverlayViewHide', _this);
26447 fromLatLngToContainerPixel: function(event)
26449 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26452 isApplied: function()
26454 return this.getGmapContext() == false ? false : true;
26457 getGmapContext: function()
26459 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26462 GMapContext: function()
26464 var position = new google.maps.LatLng(this.latitude, this.longitude);
26466 var _map = new google.maps.Map(this.el.dom, {
26469 mapTypeId: this.mapTypeId,
26470 mapTypeControl: this.mapTypeControl,
26471 disableDoubleClickZoom: this.disableDoubleClickZoom,
26472 scrollwheel: this.scrollwheel,
26473 streetViewControl: this.streetViewControl,
26474 locationName: this.locationName,
26475 draggable: this.draggable,
26476 enableAutocomplete: this.enableAutocomplete,
26477 enableReverseGeocode: this.enableReverseGeocode
26480 var _marker = new google.maps.Marker({
26481 position: position,
26483 title: this.markerTitle,
26484 draggable: this.draggable
26491 location: position,
26492 radius: this.radius,
26493 locationName: this.locationName,
26494 addressComponents: {
26495 formatted_address: null,
26496 addressLine1: null,
26497 addressLine2: null,
26499 streetNumber: null,
26503 stateOrProvince: null
26506 domContainer: this.el.dom,
26507 geodecoder: new google.maps.Geocoder()
26511 drawCircle: function(center, radius, options)
26513 if (this.gMapContext.circle != null) {
26514 this.gMapContext.circle.setMap(null);
26518 options = Roo.apply({}, options, {
26519 strokeColor: "#0000FF",
26520 strokeOpacity: .35,
26522 fillColor: "#0000FF",
26526 options.map = this.gMapContext.map;
26527 options.radius = radius;
26528 options.center = center;
26529 this.gMapContext.circle = new google.maps.Circle(options);
26530 return this.gMapContext.circle;
26536 setPosition: function(location)
26538 this.gMapContext.location = location;
26539 this.gMapContext.marker.setPosition(location);
26540 this.gMapContext.map.panTo(location);
26541 this.drawCircle(location, this.gMapContext.radius, {});
26545 if (this.gMapContext.settings.enableReverseGeocode) {
26546 this.gMapContext.geodecoder.geocode({
26547 latLng: this.gMapContext.location
26548 }, function(results, status) {
26550 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26551 _this.gMapContext.locationName = results[0].formatted_address;
26552 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26554 _this.fireEvent('positionchanged', this, location);
26561 this.fireEvent('positionchanged', this, location);
26566 google.maps.event.trigger(this.gMapContext.map, "resize");
26568 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26570 this.fireEvent('resize', this);
26573 setPositionByLatLng: function(latitude, longitude)
26575 this.setPosition(new google.maps.LatLng(latitude, longitude));
26578 getCurrentPosition: function()
26581 latitude: this.gMapContext.location.lat(),
26582 longitude: this.gMapContext.location.lng()
26586 getAddressName: function()
26588 return this.gMapContext.locationName;
26591 getAddressComponents: function()
26593 return this.gMapContext.addressComponents;
26596 address_component_from_google_geocode: function(address_components)
26600 for (var i = 0; i < address_components.length; i++) {
26601 var component = address_components[i];
26602 if (component.types.indexOf("postal_code") >= 0) {
26603 result.postalCode = component.short_name;
26604 } else if (component.types.indexOf("street_number") >= 0) {
26605 result.streetNumber = component.short_name;
26606 } else if (component.types.indexOf("route") >= 0) {
26607 result.streetName = component.short_name;
26608 } else if (component.types.indexOf("neighborhood") >= 0) {
26609 result.city = component.short_name;
26610 } else if (component.types.indexOf("locality") >= 0) {
26611 result.city = component.short_name;
26612 } else if (component.types.indexOf("sublocality") >= 0) {
26613 result.district = component.short_name;
26614 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26615 result.stateOrProvince = component.short_name;
26616 } else if (component.types.indexOf("country") >= 0) {
26617 result.country = component.short_name;
26621 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26622 result.addressLine2 = "";
26626 setZoomLevel: function(zoom)
26628 this.gMapContext.map.setZoom(zoom);
26641 this.fireEvent('show', this);
26652 this.fireEvent('hide', this);
26657 Roo.apply(Roo.bootstrap.LocationPicker, {
26659 OverlayView : function(map, options)
26661 options = options || {};
26675 * @class Roo.bootstrap.Alert
26676 * @extends Roo.bootstrap.Component
26677 * Bootstrap Alert class
26678 * @cfg {String} title The title of alert
26679 * @cfg {String} html The content of alert
26680 * @cfg {String} weight ( success | info | warning | danger )
26681 * @cfg {String} faicon font-awesomeicon
26684 * Create a new alert
26685 * @param {Object} config The config object
26689 Roo.bootstrap.Alert = function(config){
26690 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26694 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26701 getAutoCreate : function()
26710 cls : 'roo-alert-icon'
26715 cls : 'roo-alert-title',
26720 cls : 'roo-alert-text',
26727 cfg.cn[0].cls += ' fa ' + this.faicon;
26731 cfg.cls += ' alert-' + this.weight;
26737 initEvents: function()
26739 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26742 setTitle : function(str)
26744 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26747 setText : function(str)
26749 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26752 setWeight : function(weight)
26755 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26758 this.weight = weight;
26760 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26763 setIcon : function(icon)
26766 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26769 this.faicon = icon;
26771 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26792 * @class Roo.bootstrap.UploadCropbox
26793 * @extends Roo.bootstrap.Component
26794 * Bootstrap UploadCropbox class
26795 * @cfg {String} emptyText show when image has been loaded
26796 * @cfg {String} rotateNotify show when image too small to rotate
26797 * @cfg {Number} errorTimeout default 3000
26798 * @cfg {Number} minWidth default 300
26799 * @cfg {Number} minHeight default 300
26800 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26801 * @cfg {Boolean} isDocument (true|false) default false
26802 * @cfg {String} url action url
26803 * @cfg {String} paramName default 'imageUpload'
26804 * @cfg {String} method default POST
26805 * @cfg {Boolean} loadMask (true|false) default true
26806 * @cfg {Boolean} loadingText default 'Loading...'
26809 * Create a new UploadCropbox
26810 * @param {Object} config The config object
26813 Roo.bootstrap.UploadCropbox = function(config){
26814 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26818 * @event beforeselectfile
26819 * Fire before select file
26820 * @param {Roo.bootstrap.UploadCropbox} this
26822 "beforeselectfile" : true,
26825 * Fire after initEvent
26826 * @param {Roo.bootstrap.UploadCropbox} this
26831 * Fire after initEvent
26832 * @param {Roo.bootstrap.UploadCropbox} this
26833 * @param {String} data
26838 * Fire when preparing the file data
26839 * @param {Roo.bootstrap.UploadCropbox} this
26840 * @param {Object} file
26845 * Fire when get exception
26846 * @param {Roo.bootstrap.UploadCropbox} this
26847 * @param {XMLHttpRequest} xhr
26849 "exception" : true,
26851 * @event beforeloadcanvas
26852 * Fire before load the canvas
26853 * @param {Roo.bootstrap.UploadCropbox} this
26854 * @param {String} src
26856 "beforeloadcanvas" : true,
26859 * Fire when trash image
26860 * @param {Roo.bootstrap.UploadCropbox} this
26865 * Fire when download the image
26866 * @param {Roo.bootstrap.UploadCropbox} this
26870 * @event footerbuttonclick
26871 * Fire when footerbuttonclick
26872 * @param {Roo.bootstrap.UploadCropbox} this
26873 * @param {String} type
26875 "footerbuttonclick" : true,
26879 * @param {Roo.bootstrap.UploadCropbox} this
26884 * Fire when rotate the image
26885 * @param {Roo.bootstrap.UploadCropbox} this
26886 * @param {String} pos
26891 * Fire when inspect the file
26892 * @param {Roo.bootstrap.UploadCropbox} this
26893 * @param {Object} file
26898 * Fire when xhr upload the file
26899 * @param {Roo.bootstrap.UploadCropbox} this
26900 * @param {Object} data
26905 * Fire when arrange the file data
26906 * @param {Roo.bootstrap.UploadCropbox} this
26907 * @param {Object} formData
26912 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26915 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
26917 emptyText : 'Click to upload image',
26918 rotateNotify : 'Image is too small to rotate',
26919 errorTimeout : 3000,
26933 cropType : 'image/jpeg',
26935 canvasLoaded : false,
26936 isDocument : false,
26938 paramName : 'imageUpload',
26940 loadingText : 'Loading...',
26943 getAutoCreate : function()
26947 cls : 'roo-upload-cropbox',
26951 cls : 'roo-upload-cropbox-selector',
26956 cls : 'roo-upload-cropbox-body',
26957 style : 'cursor:pointer',
26961 cls : 'roo-upload-cropbox-preview'
26965 cls : 'roo-upload-cropbox-thumb'
26969 cls : 'roo-upload-cropbox-empty-notify',
26970 html : this.emptyText
26974 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
26975 html : this.rotateNotify
26981 cls : 'roo-upload-cropbox-footer',
26984 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
26994 onRender : function(ct, position)
26996 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
26998 if (this.buttons.length) {
27000 Roo.each(this.buttons, function(bb) {
27002 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27004 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27010 this.maskEl = this.el;
27014 initEvents : function()
27016 this.urlAPI = (window.createObjectURL && window) ||
27017 (window.URL && URL.revokeObjectURL && URL) ||
27018 (window.webkitURL && webkitURL);
27020 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27021 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27023 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27024 this.selectorEl.hide();
27026 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27027 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27029 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27030 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27031 this.thumbEl.hide();
27033 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27034 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27036 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27037 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27038 this.errorEl.hide();
27040 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27041 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27042 this.footerEl.hide();
27044 this.setThumbBoxSize();
27050 this.fireEvent('initial', this);
27057 window.addEventListener("resize", function() { _this.resize(); } );
27059 this.bodyEl.on('click', this.beforeSelectFile, this);
27062 this.bodyEl.on('touchstart', this.onTouchStart, this);
27063 this.bodyEl.on('touchmove', this.onTouchMove, this);
27064 this.bodyEl.on('touchend', this.onTouchEnd, this);
27068 this.bodyEl.on('mousedown', this.onMouseDown, this);
27069 this.bodyEl.on('mousemove', this.onMouseMove, this);
27070 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27071 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27072 Roo.get(document).on('mouseup', this.onMouseUp, this);
27075 this.selectorEl.on('change', this.onFileSelected, this);
27081 this.baseScale = 1;
27083 this.baseRotate = 1;
27084 this.dragable = false;
27085 this.pinching = false;
27088 this.cropData = false;
27089 this.notifyEl.dom.innerHTML = this.emptyText;
27091 this.selectorEl.dom.value = '';
27095 resize : function()
27097 if(this.fireEvent('resize', this) != false){
27098 this.setThumbBoxPosition();
27099 this.setCanvasPosition();
27103 onFooterButtonClick : function(e, el, o, type)
27106 case 'rotate-left' :
27107 this.onRotateLeft(e);
27109 case 'rotate-right' :
27110 this.onRotateRight(e);
27113 this.beforeSelectFile(e);
27128 this.fireEvent('footerbuttonclick', this, type);
27131 beforeSelectFile : function(e)
27133 e.preventDefault();
27135 if(this.fireEvent('beforeselectfile', this) != false){
27136 this.selectorEl.dom.click();
27140 onFileSelected : function(e)
27142 e.preventDefault();
27144 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27148 var file = this.selectorEl.dom.files[0];
27150 if(this.fireEvent('inspect', this, file) != false){
27151 this.prepare(file);
27156 trash : function(e)
27158 this.fireEvent('trash', this);
27161 download : function(e)
27163 this.fireEvent('download', this);
27166 loadCanvas : function(src)
27168 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27172 this.imageEl = document.createElement('img');
27176 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27178 this.imageEl.src = src;
27182 onLoadCanvas : function()
27184 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27185 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27187 this.bodyEl.un('click', this.beforeSelectFile, this);
27189 this.notifyEl.hide();
27190 this.thumbEl.show();
27191 this.footerEl.show();
27193 this.baseRotateLevel();
27195 if(this.isDocument){
27196 this.setThumbBoxSize();
27199 this.setThumbBoxPosition();
27201 this.baseScaleLevel();
27207 this.canvasLoaded = true;
27210 this.maskEl.unmask();
27215 setCanvasPosition : function()
27217 if(!this.canvasEl){
27221 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27222 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27224 this.previewEl.setLeft(pw);
27225 this.previewEl.setTop(ph);
27229 onMouseDown : function(e)
27233 this.dragable = true;
27234 this.pinching = false;
27236 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27237 this.dragable = false;
27241 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27242 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27246 onMouseMove : function(e)
27250 if(!this.canvasLoaded){
27254 if (!this.dragable){
27258 var minX = Math.ceil(this.thumbEl.getLeft(true));
27259 var minY = Math.ceil(this.thumbEl.getTop(true));
27261 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27262 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27264 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27265 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27267 x = x - this.mouseX;
27268 y = y - this.mouseY;
27270 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27271 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27273 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27274 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27276 this.previewEl.setLeft(bgX);
27277 this.previewEl.setTop(bgY);
27279 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27280 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27283 onMouseUp : function(e)
27287 this.dragable = false;
27290 onMouseWheel : function(e)
27294 this.startScale = this.scale;
27296 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27298 if(!this.zoomable()){
27299 this.scale = this.startScale;
27308 zoomable : function()
27310 var minScale = this.thumbEl.getWidth() / this.minWidth;
27312 if(this.minWidth < this.minHeight){
27313 minScale = this.thumbEl.getHeight() / this.minHeight;
27316 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27317 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27321 (this.rotate == 0 || this.rotate == 180) &&
27323 width > this.imageEl.OriginWidth ||
27324 height > this.imageEl.OriginHeight ||
27325 (width < this.minWidth && height < this.minHeight)
27333 (this.rotate == 90 || this.rotate == 270) &&
27335 width > this.imageEl.OriginWidth ||
27336 height > this.imageEl.OriginHeight ||
27337 (width < this.minHeight && height < this.minWidth)
27344 !this.isDocument &&
27345 (this.rotate == 0 || this.rotate == 180) &&
27347 width < this.minWidth ||
27348 width > this.imageEl.OriginWidth ||
27349 height < this.minHeight ||
27350 height > this.imageEl.OriginHeight
27357 !this.isDocument &&
27358 (this.rotate == 90 || this.rotate == 270) &&
27360 width < this.minHeight ||
27361 width > this.imageEl.OriginWidth ||
27362 height < this.minWidth ||
27363 height > this.imageEl.OriginHeight
27373 onRotateLeft : function(e)
27375 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27377 var minScale = this.thumbEl.getWidth() / this.minWidth;
27379 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27380 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27382 this.startScale = this.scale;
27384 while (this.getScaleLevel() < minScale){
27386 this.scale = this.scale + 1;
27388 if(!this.zoomable()){
27393 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27394 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27399 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27406 this.scale = this.startScale;
27408 this.onRotateFail();
27413 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27415 if(this.isDocument){
27416 this.setThumbBoxSize();
27417 this.setThumbBoxPosition();
27418 this.setCanvasPosition();
27423 this.fireEvent('rotate', this, 'left');
27427 onRotateRight : function(e)
27429 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27431 var minScale = this.thumbEl.getWidth() / this.minWidth;
27433 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27434 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27436 this.startScale = this.scale;
27438 while (this.getScaleLevel() < minScale){
27440 this.scale = this.scale + 1;
27442 if(!this.zoomable()){
27447 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27448 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27453 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27460 this.scale = this.startScale;
27462 this.onRotateFail();
27467 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27469 if(this.isDocument){
27470 this.setThumbBoxSize();
27471 this.setThumbBoxPosition();
27472 this.setCanvasPosition();
27477 this.fireEvent('rotate', this, 'right');
27480 onRotateFail : function()
27482 this.errorEl.show(true);
27486 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27491 this.previewEl.dom.innerHTML = '';
27493 var canvasEl = document.createElement("canvas");
27495 var contextEl = canvasEl.getContext("2d");
27497 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27498 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27499 var center = this.imageEl.OriginWidth / 2;
27501 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27502 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27503 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27504 center = this.imageEl.OriginHeight / 2;
27507 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27509 contextEl.translate(center, center);
27510 contextEl.rotate(this.rotate * Math.PI / 180);
27512 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27514 this.canvasEl = document.createElement("canvas");
27516 this.contextEl = this.canvasEl.getContext("2d");
27518 switch (this.rotate) {
27521 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27522 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27524 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27529 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27530 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27532 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27533 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);
27537 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27542 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27543 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27545 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27546 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);
27550 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);
27555 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27556 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27558 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27559 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27563 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);
27570 this.previewEl.appendChild(this.canvasEl);
27572 this.setCanvasPosition();
27577 if(!this.canvasLoaded){
27581 var imageCanvas = document.createElement("canvas");
27583 var imageContext = imageCanvas.getContext("2d");
27585 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27586 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27588 var center = imageCanvas.width / 2;
27590 imageContext.translate(center, center);
27592 imageContext.rotate(this.rotate * Math.PI / 180);
27594 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27596 var canvas = document.createElement("canvas");
27598 var context = canvas.getContext("2d");
27600 canvas.width = this.minWidth;
27601 canvas.height = this.minHeight;
27603 switch (this.rotate) {
27606 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27607 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27609 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27610 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27612 var targetWidth = this.minWidth - 2 * x;
27613 var targetHeight = this.minHeight - 2 * y;
27617 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27618 scale = targetWidth / width;
27621 if(x > 0 && y == 0){
27622 scale = targetHeight / height;
27625 if(x > 0 && y > 0){
27626 scale = targetWidth / width;
27628 if(width < height){
27629 scale = targetHeight / height;
27633 context.scale(scale, scale);
27635 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27636 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27638 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27639 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27641 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27646 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27647 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27649 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27650 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27652 var targetWidth = this.minWidth - 2 * x;
27653 var targetHeight = this.minHeight - 2 * y;
27657 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27658 scale = targetWidth / width;
27661 if(x > 0 && y == 0){
27662 scale = targetHeight / height;
27665 if(x > 0 && y > 0){
27666 scale = targetWidth / width;
27668 if(width < height){
27669 scale = targetHeight / height;
27673 context.scale(scale, scale);
27675 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27676 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27678 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27679 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27681 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27683 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27688 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27689 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27691 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27692 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27694 var targetWidth = this.minWidth - 2 * x;
27695 var targetHeight = this.minHeight - 2 * y;
27699 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27700 scale = targetWidth / width;
27703 if(x > 0 && y == 0){
27704 scale = targetHeight / height;
27707 if(x > 0 && y > 0){
27708 scale = targetWidth / width;
27710 if(width < height){
27711 scale = targetHeight / height;
27715 context.scale(scale, scale);
27717 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27718 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27720 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27721 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27723 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27724 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27726 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27731 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27732 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27734 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27735 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27737 var targetWidth = this.minWidth - 2 * x;
27738 var targetHeight = this.minHeight - 2 * y;
27742 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27743 scale = targetWidth / width;
27746 if(x > 0 && y == 0){
27747 scale = targetHeight / height;
27750 if(x > 0 && y > 0){
27751 scale = targetWidth / width;
27753 if(width < height){
27754 scale = targetHeight / height;
27758 context.scale(scale, scale);
27760 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27761 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27763 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27764 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27766 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27768 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27775 this.cropData = canvas.toDataURL(this.cropType);
27777 if(this.fireEvent('crop', this, this.cropData) !== false){
27778 this.process(this.file, this.cropData);
27785 setThumbBoxSize : function()
27789 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27790 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27791 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27793 this.minWidth = width;
27794 this.minHeight = height;
27796 if(this.rotate == 90 || this.rotate == 270){
27797 this.minWidth = height;
27798 this.minHeight = width;
27803 width = Math.ceil(this.minWidth * height / this.minHeight);
27805 if(this.minWidth > this.minHeight){
27807 height = Math.ceil(this.minHeight * width / this.minWidth);
27810 this.thumbEl.setStyle({
27811 width : width + 'px',
27812 height : height + 'px'
27819 setThumbBoxPosition : function()
27821 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27822 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27824 this.thumbEl.setLeft(x);
27825 this.thumbEl.setTop(y);
27829 baseRotateLevel : function()
27831 this.baseRotate = 1;
27834 typeof(this.exif) != 'undefined' &&
27835 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27836 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27838 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27841 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27845 baseScaleLevel : function()
27849 if(this.isDocument){
27851 if(this.baseRotate == 6 || this.baseRotate == 8){
27853 height = this.thumbEl.getHeight();
27854 this.baseScale = height / this.imageEl.OriginWidth;
27856 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27857 width = this.thumbEl.getWidth();
27858 this.baseScale = width / this.imageEl.OriginHeight;
27864 height = this.thumbEl.getHeight();
27865 this.baseScale = height / this.imageEl.OriginHeight;
27867 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27868 width = this.thumbEl.getWidth();
27869 this.baseScale = width / this.imageEl.OriginWidth;
27875 if(this.baseRotate == 6 || this.baseRotate == 8){
27877 width = this.thumbEl.getHeight();
27878 this.baseScale = width / this.imageEl.OriginHeight;
27880 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27881 height = this.thumbEl.getWidth();
27882 this.baseScale = height / this.imageEl.OriginHeight;
27885 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27886 height = this.thumbEl.getWidth();
27887 this.baseScale = height / this.imageEl.OriginHeight;
27889 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27890 width = this.thumbEl.getHeight();
27891 this.baseScale = width / this.imageEl.OriginWidth;
27898 width = this.thumbEl.getWidth();
27899 this.baseScale = width / this.imageEl.OriginWidth;
27901 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27902 height = this.thumbEl.getHeight();
27903 this.baseScale = height / this.imageEl.OriginHeight;
27906 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27908 height = this.thumbEl.getHeight();
27909 this.baseScale = height / this.imageEl.OriginHeight;
27911 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27912 width = this.thumbEl.getWidth();
27913 this.baseScale = width / this.imageEl.OriginWidth;
27921 getScaleLevel : function()
27923 return this.baseScale * Math.pow(1.1, this.scale);
27926 onTouchStart : function(e)
27928 if(!this.canvasLoaded){
27929 this.beforeSelectFile(e);
27933 var touches = e.browserEvent.touches;
27939 if(touches.length == 1){
27940 this.onMouseDown(e);
27944 if(touches.length != 2){
27950 for(var i = 0, finger; finger = touches[i]; i++){
27951 coords.push(finger.pageX, finger.pageY);
27954 var x = Math.pow(coords[0] - coords[2], 2);
27955 var y = Math.pow(coords[1] - coords[3], 2);
27957 this.startDistance = Math.sqrt(x + y);
27959 this.startScale = this.scale;
27961 this.pinching = true;
27962 this.dragable = false;
27966 onTouchMove : function(e)
27968 if(!this.pinching && !this.dragable){
27972 var touches = e.browserEvent.touches;
27979 this.onMouseMove(e);
27985 for(var i = 0, finger; finger = touches[i]; i++){
27986 coords.push(finger.pageX, finger.pageY);
27989 var x = Math.pow(coords[0] - coords[2], 2);
27990 var y = Math.pow(coords[1] - coords[3], 2);
27992 this.endDistance = Math.sqrt(x + y);
27994 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
27996 if(!this.zoomable()){
27997 this.scale = this.startScale;
28005 onTouchEnd : function(e)
28007 this.pinching = false;
28008 this.dragable = false;
28012 process : function(file, crop)
28015 this.maskEl.mask(this.loadingText);
28018 this.xhr = new XMLHttpRequest();
28020 file.xhr = this.xhr;
28022 this.xhr.open(this.method, this.url, true);
28025 "Accept": "application/json",
28026 "Cache-Control": "no-cache",
28027 "X-Requested-With": "XMLHttpRequest"
28030 for (var headerName in headers) {
28031 var headerValue = headers[headerName];
28033 this.xhr.setRequestHeader(headerName, headerValue);
28039 this.xhr.onload = function()
28041 _this.xhrOnLoad(_this.xhr);
28044 this.xhr.onerror = function()
28046 _this.xhrOnError(_this.xhr);
28049 var formData = new FormData();
28051 formData.append('returnHTML', 'NO');
28054 formData.append('crop', crop);
28057 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28058 formData.append(this.paramName, file, file.name);
28061 if(typeof(file.filename) != 'undefined'){
28062 formData.append('filename', file.filename);
28065 if(typeof(file.mimetype) != 'undefined'){
28066 formData.append('mimetype', file.mimetype);
28069 if(this.fireEvent('arrange', this, formData) != false){
28070 this.xhr.send(formData);
28074 xhrOnLoad : function(xhr)
28077 this.maskEl.unmask();
28080 if (xhr.readyState !== 4) {
28081 this.fireEvent('exception', this, xhr);
28085 var response = Roo.decode(xhr.responseText);
28087 if(!response.success){
28088 this.fireEvent('exception', this, xhr);
28092 var response = Roo.decode(xhr.responseText);
28094 this.fireEvent('upload', this, response);
28098 xhrOnError : function()
28101 this.maskEl.unmask();
28104 Roo.log('xhr on error');
28106 var response = Roo.decode(xhr.responseText);
28112 prepare : function(file)
28115 this.maskEl.mask(this.loadingText);
28121 if(typeof(file) === 'string'){
28122 this.loadCanvas(file);
28126 if(!file || !this.urlAPI){
28131 this.cropType = file.type;
28135 if(this.fireEvent('prepare', this, this.file) != false){
28137 var reader = new FileReader();
28139 reader.onload = function (e) {
28140 if (e.target.error) {
28141 Roo.log(e.target.error);
28145 var buffer = e.target.result,
28146 dataView = new DataView(buffer),
28148 maxOffset = dataView.byteLength - 4,
28152 if (dataView.getUint16(0) === 0xffd8) {
28153 while (offset < maxOffset) {
28154 markerBytes = dataView.getUint16(offset);
28156 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28157 markerLength = dataView.getUint16(offset + 2) + 2;
28158 if (offset + markerLength > dataView.byteLength) {
28159 Roo.log('Invalid meta data: Invalid segment size.');
28163 if(markerBytes == 0xffe1){
28164 _this.parseExifData(
28171 offset += markerLength;
28181 var url = _this.urlAPI.createObjectURL(_this.file);
28183 _this.loadCanvas(url);
28188 reader.readAsArrayBuffer(this.file);
28194 parseExifData : function(dataView, offset, length)
28196 var tiffOffset = offset + 10,
28200 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28201 // No Exif data, might be XMP data instead
28205 // Check for the ASCII code for "Exif" (0x45786966):
28206 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28207 // No Exif data, might be XMP data instead
28210 if (tiffOffset + 8 > dataView.byteLength) {
28211 Roo.log('Invalid Exif data: Invalid segment size.');
28214 // Check for the two null bytes:
28215 if (dataView.getUint16(offset + 8) !== 0x0000) {
28216 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28219 // Check the byte alignment:
28220 switch (dataView.getUint16(tiffOffset)) {
28222 littleEndian = true;
28225 littleEndian = false;
28228 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28231 // Check for the TIFF tag marker (0x002A):
28232 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28233 Roo.log('Invalid Exif data: Missing TIFF marker.');
28236 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28237 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28239 this.parseExifTags(
28242 tiffOffset + dirOffset,
28247 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28252 if (dirOffset + 6 > dataView.byteLength) {
28253 Roo.log('Invalid Exif data: Invalid directory offset.');
28256 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28257 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28258 if (dirEndOffset + 4 > dataView.byteLength) {
28259 Roo.log('Invalid Exif data: Invalid directory size.');
28262 for (i = 0; i < tagsNumber; i += 1) {
28266 dirOffset + 2 + 12 * i, // tag offset
28270 // Return the offset to the next directory:
28271 return dataView.getUint32(dirEndOffset, littleEndian);
28274 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28276 var tag = dataView.getUint16(offset, littleEndian);
28278 this.exif[tag] = this.getExifValue(
28282 dataView.getUint16(offset + 2, littleEndian), // tag type
28283 dataView.getUint32(offset + 4, littleEndian), // tag length
28288 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28290 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28299 Roo.log('Invalid Exif data: Invalid tag type.');
28303 tagSize = tagType.size * length;
28304 // Determine if the value is contained in the dataOffset bytes,
28305 // or if the value at the dataOffset is a pointer to the actual data:
28306 dataOffset = tagSize > 4 ?
28307 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28308 if (dataOffset + tagSize > dataView.byteLength) {
28309 Roo.log('Invalid Exif data: Invalid data offset.');
28312 if (length === 1) {
28313 return tagType.getValue(dataView, dataOffset, littleEndian);
28316 for (i = 0; i < length; i += 1) {
28317 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28320 if (tagType.ascii) {
28322 // Concatenate the chars:
28323 for (i = 0; i < values.length; i += 1) {
28325 // Ignore the terminating NULL byte(s):
28326 if (c === '\u0000') {
28338 Roo.apply(Roo.bootstrap.UploadCropbox, {
28340 'Orientation': 0x0112
28344 1: 0, //'top-left',
28346 3: 180, //'bottom-right',
28347 // 4: 'bottom-left',
28349 6: 90, //'right-top',
28350 // 7: 'right-bottom',
28351 8: 270 //'left-bottom'
28355 // byte, 8-bit unsigned int:
28357 getValue: function (dataView, dataOffset) {
28358 return dataView.getUint8(dataOffset);
28362 // ascii, 8-bit byte:
28364 getValue: function (dataView, dataOffset) {
28365 return String.fromCharCode(dataView.getUint8(dataOffset));
28370 // short, 16 bit int:
28372 getValue: function (dataView, dataOffset, littleEndian) {
28373 return dataView.getUint16(dataOffset, littleEndian);
28377 // long, 32 bit int:
28379 getValue: function (dataView, dataOffset, littleEndian) {
28380 return dataView.getUint32(dataOffset, littleEndian);
28384 // rational = two long values, first is numerator, second is denominator:
28386 getValue: function (dataView, dataOffset, littleEndian) {
28387 return dataView.getUint32(dataOffset, littleEndian) /
28388 dataView.getUint32(dataOffset + 4, littleEndian);
28392 // slong, 32 bit signed int:
28394 getValue: function (dataView, dataOffset, littleEndian) {
28395 return dataView.getInt32(dataOffset, littleEndian);
28399 // srational, two slongs, first is numerator, second is denominator:
28401 getValue: function (dataView, dataOffset, littleEndian) {
28402 return dataView.getInt32(dataOffset, littleEndian) /
28403 dataView.getInt32(dataOffset + 4, littleEndian);
28413 cls : 'btn-group roo-upload-cropbox-rotate-left',
28414 action : 'rotate-left',
28418 cls : 'btn btn-default',
28419 html : '<i class="fa fa-undo"></i>'
28425 cls : 'btn-group roo-upload-cropbox-picture',
28426 action : 'picture',
28430 cls : 'btn btn-default',
28431 html : '<i class="fa fa-picture-o"></i>'
28437 cls : 'btn-group roo-upload-cropbox-rotate-right',
28438 action : 'rotate-right',
28442 cls : 'btn btn-default',
28443 html : '<i class="fa fa-repeat"></i>'
28451 cls : 'btn-group roo-upload-cropbox-rotate-left',
28452 action : 'rotate-left',
28456 cls : 'btn btn-default',
28457 html : '<i class="fa fa-undo"></i>'
28463 cls : 'btn-group roo-upload-cropbox-download',
28464 action : 'download',
28468 cls : 'btn btn-default',
28469 html : '<i class="fa fa-download"></i>'
28475 cls : 'btn-group roo-upload-cropbox-crop',
28480 cls : 'btn btn-default',
28481 html : '<i class="fa fa-crop"></i>'
28487 cls : 'btn-group roo-upload-cropbox-trash',
28492 cls : 'btn btn-default',
28493 html : '<i class="fa fa-trash"></i>'
28499 cls : 'btn-group roo-upload-cropbox-rotate-right',
28500 action : 'rotate-right',
28504 cls : 'btn btn-default',
28505 html : '<i class="fa fa-repeat"></i>'
28513 cls : 'btn-group roo-upload-cropbox-rotate-left',
28514 action : 'rotate-left',
28518 cls : 'btn btn-default',
28519 html : '<i class="fa fa-undo"></i>'
28525 cls : 'btn-group roo-upload-cropbox-rotate-right',
28526 action : 'rotate-right',
28530 cls : 'btn btn-default',
28531 html : '<i class="fa fa-repeat"></i>'
28544 * @class Roo.bootstrap.DocumentManager
28545 * @extends Roo.bootstrap.Component
28546 * Bootstrap DocumentManager class
28547 * @cfg {String} paramName default 'imageUpload'
28548 * @cfg {String} toolTipName default 'filename'
28549 * @cfg {String} method default POST
28550 * @cfg {String} url action url
28551 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28552 * @cfg {Boolean} multiple multiple upload default true
28553 * @cfg {Number} thumbSize default 300
28554 * @cfg {String} fieldLabel
28555 * @cfg {Number} labelWidth default 4
28556 * @cfg {String} labelAlign (left|top) default left
28557 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28558 * @cfg {Number} labellg set the width of label (1-12)
28559 * @cfg {Number} labelmd set the width of label (1-12)
28560 * @cfg {Number} labelsm set the width of label (1-12)
28561 * @cfg {Number} labelxs set the width of label (1-12)
28564 * Create a new DocumentManager
28565 * @param {Object} config The config object
28568 Roo.bootstrap.DocumentManager = function(config){
28569 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28572 this.delegates = [];
28577 * Fire when initial the DocumentManager
28578 * @param {Roo.bootstrap.DocumentManager} this
28583 * inspect selected file
28584 * @param {Roo.bootstrap.DocumentManager} this
28585 * @param {File} file
28590 * Fire when xhr load exception
28591 * @param {Roo.bootstrap.DocumentManager} this
28592 * @param {XMLHttpRequest} xhr
28594 "exception" : true,
28596 * @event afterupload
28597 * Fire when xhr load exception
28598 * @param {Roo.bootstrap.DocumentManager} this
28599 * @param {XMLHttpRequest} xhr
28601 "afterupload" : true,
28604 * prepare the form data
28605 * @param {Roo.bootstrap.DocumentManager} this
28606 * @param {Object} formData
28611 * Fire when remove the file
28612 * @param {Roo.bootstrap.DocumentManager} this
28613 * @param {Object} file
28618 * Fire after refresh the file
28619 * @param {Roo.bootstrap.DocumentManager} this
28624 * Fire after click the image
28625 * @param {Roo.bootstrap.DocumentManager} this
28626 * @param {Object} file
28631 * Fire when upload a image and editable set to true
28632 * @param {Roo.bootstrap.DocumentManager} this
28633 * @param {Object} file
28637 * @event beforeselectfile
28638 * Fire before select file
28639 * @param {Roo.bootstrap.DocumentManager} this
28641 "beforeselectfile" : true,
28644 * Fire before process file
28645 * @param {Roo.bootstrap.DocumentManager} this
28646 * @param {Object} file
28650 * @event previewrendered
28651 * Fire when preview rendered
28652 * @param {Roo.bootstrap.DocumentManager} this
28653 * @param {Object} file
28655 "previewrendered" : true
28660 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28669 paramName : 'imageUpload',
28670 toolTipName : 'filename',
28673 labelAlign : 'left',
28683 getAutoCreate : function()
28685 var managerWidget = {
28687 cls : 'roo-document-manager',
28691 cls : 'roo-document-manager-selector',
28696 cls : 'roo-document-manager-uploader',
28700 cls : 'roo-document-manager-upload-btn',
28701 html : '<i class="fa fa-plus"></i>'
28712 cls : 'column col-md-12',
28717 if(this.fieldLabel.length){
28722 cls : 'column col-md-12',
28723 html : this.fieldLabel
28727 cls : 'column col-md-12',
28732 if(this.labelAlign == 'left'){
28737 html : this.fieldLabel
28746 if(this.labelWidth > 12){
28747 content[0].style = "width: " + this.labelWidth + 'px';
28750 if(this.labelWidth < 13 && this.labelmd == 0){
28751 this.labelmd = this.labelWidth;
28754 if(this.labellg > 0){
28755 content[0].cls += ' col-lg-' + this.labellg;
28756 content[1].cls += ' col-lg-' + (12 - this.labellg);
28759 if(this.labelmd > 0){
28760 content[0].cls += ' col-md-' + this.labelmd;
28761 content[1].cls += ' col-md-' + (12 - this.labelmd);
28764 if(this.labelsm > 0){
28765 content[0].cls += ' col-sm-' + this.labelsm;
28766 content[1].cls += ' col-sm-' + (12 - this.labelsm);
28769 if(this.labelxs > 0){
28770 content[0].cls += ' col-xs-' + this.labelxs;
28771 content[1].cls += ' col-xs-' + (12 - this.labelxs);
28779 cls : 'row clearfix',
28787 initEvents : function()
28789 this.managerEl = this.el.select('.roo-document-manager', true).first();
28790 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28792 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28793 this.selectorEl.hide();
28796 this.selectorEl.attr('multiple', 'multiple');
28799 this.selectorEl.on('change', this.onFileSelected, this);
28801 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28802 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28804 this.uploader.on('click', this.onUploaderClick, this);
28806 this.renderProgressDialog();
28810 window.addEventListener("resize", function() { _this.refresh(); } );
28812 this.fireEvent('initial', this);
28815 renderProgressDialog : function()
28819 this.progressDialog = new Roo.bootstrap.Modal({
28820 cls : 'roo-document-manager-progress-dialog',
28821 allow_close : false,
28831 btnclick : function() {
28832 _this.uploadCancel();
28838 this.progressDialog.render(Roo.get(document.body));
28840 this.progress = new Roo.bootstrap.Progress({
28841 cls : 'roo-document-manager-progress',
28846 this.progress.render(this.progressDialog.getChildContainer());
28848 this.progressBar = new Roo.bootstrap.ProgressBar({
28849 cls : 'roo-document-manager-progress-bar',
28852 aria_valuemax : 12,
28856 this.progressBar.render(this.progress.getChildContainer());
28859 onUploaderClick : function(e)
28861 e.preventDefault();
28863 if(this.fireEvent('beforeselectfile', this) != false){
28864 this.selectorEl.dom.click();
28869 onFileSelected : function(e)
28871 e.preventDefault();
28873 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28877 Roo.each(this.selectorEl.dom.files, function(file){
28878 if(this.fireEvent('inspect', this, file) != false){
28879 this.files.push(file);
28889 this.selectorEl.dom.value = '';
28891 if(!this.files || !this.files.length){
28895 if(this.boxes > 0 && this.files.length > this.boxes){
28896 this.files = this.files.slice(0, this.boxes);
28899 this.uploader.show();
28901 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28902 this.uploader.hide();
28911 Roo.each(this.files, function(file){
28913 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28914 var f = this.renderPreview(file);
28919 if(file.type.indexOf('image') != -1){
28920 this.delegates.push(
28922 _this.process(file);
28923 }).createDelegate(this)
28931 _this.process(file);
28932 }).createDelegate(this)
28937 this.files = files;
28939 this.delegates = this.delegates.concat(docs);
28941 if(!this.delegates.length){
28946 this.progressBar.aria_valuemax = this.delegates.length;
28953 arrange : function()
28955 if(!this.delegates.length){
28956 this.progressDialog.hide();
28961 var delegate = this.delegates.shift();
28963 this.progressDialog.show();
28965 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
28967 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
28972 refresh : function()
28974 this.uploader.show();
28976 if(this.boxes > 0 && this.files.length > this.boxes - 1){
28977 this.uploader.hide();
28980 Roo.isTouch ? this.closable(false) : this.closable(true);
28982 this.fireEvent('refresh', this);
28985 onRemove : function(e, el, o)
28987 e.preventDefault();
28989 this.fireEvent('remove', this, o);
28993 remove : function(o)
28997 Roo.each(this.files, function(file){
28998 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29007 this.files = files;
29014 Roo.each(this.files, function(file){
29019 file.target.remove();
29028 onClick : function(e, el, o)
29030 e.preventDefault();
29032 this.fireEvent('click', this, o);
29036 closable : function(closable)
29038 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29040 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29052 xhrOnLoad : function(xhr)
29054 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29058 if (xhr.readyState !== 4) {
29060 this.fireEvent('exception', this, xhr);
29064 var response = Roo.decode(xhr.responseText);
29066 if(!response.success){
29068 this.fireEvent('exception', this, xhr);
29072 var file = this.renderPreview(response.data);
29074 this.files.push(file);
29078 this.fireEvent('afterupload', this, xhr);
29082 xhrOnError : function(xhr)
29084 Roo.log('xhr on error');
29086 var response = Roo.decode(xhr.responseText);
29093 process : function(file)
29095 if(this.fireEvent('process', this, file) !== false){
29096 if(this.editable && file.type.indexOf('image') != -1){
29097 this.fireEvent('edit', this, file);
29101 this.uploadStart(file, false);
29108 uploadStart : function(file, crop)
29110 this.xhr = new XMLHttpRequest();
29112 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29117 file.xhr = this.xhr;
29119 this.managerEl.createChild({
29121 cls : 'roo-document-manager-loading',
29125 tooltip : file.name,
29126 cls : 'roo-document-manager-thumb',
29127 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29133 this.xhr.open(this.method, this.url, true);
29136 "Accept": "application/json",
29137 "Cache-Control": "no-cache",
29138 "X-Requested-With": "XMLHttpRequest"
29141 for (var headerName in headers) {
29142 var headerValue = headers[headerName];
29144 this.xhr.setRequestHeader(headerName, headerValue);
29150 this.xhr.onload = function()
29152 _this.xhrOnLoad(_this.xhr);
29155 this.xhr.onerror = function()
29157 _this.xhrOnError(_this.xhr);
29160 var formData = new FormData();
29162 formData.append('returnHTML', 'NO');
29165 formData.append('crop', crop);
29168 formData.append(this.paramName, file, file.name);
29175 if(this.fireEvent('prepare', this, formData, options) != false){
29177 if(options.manually){
29181 this.xhr.send(formData);
29185 this.uploadCancel();
29188 uploadCancel : function()
29194 this.delegates = [];
29196 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29203 renderPreview : function(file)
29205 if(typeof(file.target) != 'undefined' && file.target){
29209 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29211 var previewEl = this.managerEl.createChild({
29213 cls : 'roo-document-manager-preview',
29217 tooltip : file[this.toolTipName],
29218 cls : 'roo-document-manager-thumb',
29219 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29224 html : '<i class="fa fa-times-circle"></i>'
29229 var close = previewEl.select('button.close', true).first();
29231 close.on('click', this.onRemove, this, file);
29233 file.target = previewEl;
29235 var image = previewEl.select('img', true).first();
29239 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29241 image.on('click', this.onClick, this, file);
29243 this.fireEvent('previewrendered', this, file);
29249 onPreviewLoad : function(file, image)
29251 if(typeof(file.target) == 'undefined' || !file.target){
29255 var width = image.dom.naturalWidth || image.dom.width;
29256 var height = image.dom.naturalHeight || image.dom.height;
29258 if(width > height){
29259 file.target.addClass('wide');
29263 file.target.addClass('tall');
29268 uploadFromSource : function(file, crop)
29270 this.xhr = new XMLHttpRequest();
29272 this.managerEl.createChild({
29274 cls : 'roo-document-manager-loading',
29278 tooltip : file.name,
29279 cls : 'roo-document-manager-thumb',
29280 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29286 this.xhr.open(this.method, this.url, true);
29289 "Accept": "application/json",
29290 "Cache-Control": "no-cache",
29291 "X-Requested-With": "XMLHttpRequest"
29294 for (var headerName in headers) {
29295 var headerValue = headers[headerName];
29297 this.xhr.setRequestHeader(headerName, headerValue);
29303 this.xhr.onload = function()
29305 _this.xhrOnLoad(_this.xhr);
29308 this.xhr.onerror = function()
29310 _this.xhrOnError(_this.xhr);
29313 var formData = new FormData();
29315 formData.append('returnHTML', 'NO');
29317 formData.append('crop', crop);
29319 if(typeof(file.filename) != 'undefined'){
29320 formData.append('filename', file.filename);
29323 if(typeof(file.mimetype) != 'undefined'){
29324 formData.append('mimetype', file.mimetype);
29329 if(this.fireEvent('prepare', this, formData) != false){
29330 this.xhr.send(formData);
29340 * @class Roo.bootstrap.DocumentViewer
29341 * @extends Roo.bootstrap.Component
29342 * Bootstrap DocumentViewer class
29343 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29344 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29347 * Create a new DocumentViewer
29348 * @param {Object} config The config object
29351 Roo.bootstrap.DocumentViewer = function(config){
29352 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29357 * Fire after initEvent
29358 * @param {Roo.bootstrap.DocumentViewer} this
29364 * @param {Roo.bootstrap.DocumentViewer} this
29369 * Fire after download button
29370 * @param {Roo.bootstrap.DocumentViewer} this
29375 * Fire after trash button
29376 * @param {Roo.bootstrap.DocumentViewer} this
29383 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29385 showDownload : true,
29389 getAutoCreate : function()
29393 cls : 'roo-document-viewer',
29397 cls : 'roo-document-viewer-body',
29401 cls : 'roo-document-viewer-thumb',
29405 cls : 'roo-document-viewer-image'
29413 cls : 'roo-document-viewer-footer',
29416 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29420 cls : 'btn-group roo-document-viewer-download',
29424 cls : 'btn btn-default',
29425 html : '<i class="fa fa-download"></i>'
29431 cls : 'btn-group roo-document-viewer-trash',
29435 cls : 'btn btn-default',
29436 html : '<i class="fa fa-trash"></i>'
29449 initEvents : function()
29451 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29452 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29454 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29455 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29457 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29458 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29460 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29461 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29463 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29464 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29466 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29467 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29469 this.bodyEl.on('click', this.onClick, this);
29470 this.downloadBtn.on('click', this.onDownload, this);
29471 this.trashBtn.on('click', this.onTrash, this);
29473 this.downloadBtn.hide();
29474 this.trashBtn.hide();
29476 if(this.showDownload){
29477 this.downloadBtn.show();
29480 if(this.showTrash){
29481 this.trashBtn.show();
29484 if(!this.showDownload && !this.showTrash) {
29485 this.footerEl.hide();
29490 initial : function()
29492 this.fireEvent('initial', this);
29496 onClick : function(e)
29498 e.preventDefault();
29500 this.fireEvent('click', this);
29503 onDownload : function(e)
29505 e.preventDefault();
29507 this.fireEvent('download', this);
29510 onTrash : function(e)
29512 e.preventDefault();
29514 this.fireEvent('trash', this);
29526 * @class Roo.bootstrap.NavProgressBar
29527 * @extends Roo.bootstrap.Component
29528 * Bootstrap NavProgressBar class
29531 * Create a new nav progress bar
29532 * @param {Object} config The config object
29535 Roo.bootstrap.NavProgressBar = function(config){
29536 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29538 this.bullets = this.bullets || [];
29540 // Roo.bootstrap.NavProgressBar.register(this);
29544 * Fires when the active item changes
29545 * @param {Roo.bootstrap.NavProgressBar} this
29546 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29547 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29554 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29559 getAutoCreate : function()
29561 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29565 cls : 'roo-navigation-bar-group',
29569 cls : 'roo-navigation-top-bar'
29573 cls : 'roo-navigation-bullets-bar',
29577 cls : 'roo-navigation-bar'
29584 cls : 'roo-navigation-bottom-bar'
29594 initEvents: function()
29599 onRender : function(ct, position)
29601 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29603 if(this.bullets.length){
29604 Roo.each(this.bullets, function(b){
29613 addItem : function(cfg)
29615 var item = new Roo.bootstrap.NavProgressItem(cfg);
29617 item.parentId = this.id;
29618 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29621 var top = new Roo.bootstrap.Element({
29623 cls : 'roo-navigation-bar-text'
29626 var bottom = new Roo.bootstrap.Element({
29628 cls : 'roo-navigation-bar-text'
29631 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29632 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29634 var topText = new Roo.bootstrap.Element({
29636 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29639 var bottomText = new Roo.bootstrap.Element({
29641 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29644 topText.onRender(top.el, null);
29645 bottomText.onRender(bottom.el, null);
29648 item.bottomEl = bottom;
29651 this.barItems.push(item);
29656 getActive : function()
29658 var active = false;
29660 Roo.each(this.barItems, function(v){
29662 if (!v.isActive()) {
29674 setActiveItem : function(item)
29678 Roo.each(this.barItems, function(v){
29679 if (v.rid == item.rid) {
29683 if (v.isActive()) {
29684 v.setActive(false);
29689 item.setActive(true);
29691 this.fireEvent('changed', this, item, prev);
29694 getBarItem: function(rid)
29698 Roo.each(this.barItems, function(e) {
29699 if (e.rid != rid) {
29710 indexOfItem : function(item)
29714 Roo.each(this.barItems, function(v, i){
29716 if (v.rid != item.rid) {
29727 setActiveNext : function()
29729 var i = this.indexOfItem(this.getActive());
29731 if (i > this.barItems.length) {
29735 this.setActiveItem(this.barItems[i+1]);
29738 setActivePrev : function()
29740 var i = this.indexOfItem(this.getActive());
29746 this.setActiveItem(this.barItems[i-1]);
29749 format : function()
29751 if(!this.barItems.length){
29755 var width = 100 / this.barItems.length;
29757 Roo.each(this.barItems, function(i){
29758 i.el.setStyle('width', width + '%');
29759 i.topEl.el.setStyle('width', width + '%');
29760 i.bottomEl.el.setStyle('width', width + '%');
29769 * Nav Progress Item
29774 * @class Roo.bootstrap.NavProgressItem
29775 * @extends Roo.bootstrap.Component
29776 * Bootstrap NavProgressItem class
29777 * @cfg {String} rid the reference id
29778 * @cfg {Boolean} active (true|false) Is item active default false
29779 * @cfg {Boolean} disabled (true|false) Is item active default false
29780 * @cfg {String} html
29781 * @cfg {String} position (top|bottom) text position default bottom
29782 * @cfg {String} icon show icon instead of number
29785 * Create a new NavProgressItem
29786 * @param {Object} config The config object
29788 Roo.bootstrap.NavProgressItem = function(config){
29789 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29794 * The raw click event for the entire grid.
29795 * @param {Roo.bootstrap.NavProgressItem} this
29796 * @param {Roo.EventObject} e
29803 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
29809 position : 'bottom',
29812 getAutoCreate : function()
29814 var iconCls = 'roo-navigation-bar-item-icon';
29816 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29820 cls: 'roo-navigation-bar-item',
29830 cfg.cls += ' active';
29833 cfg.cls += ' disabled';
29839 disable : function()
29841 this.setDisabled(true);
29844 enable : function()
29846 this.setDisabled(false);
29849 initEvents: function()
29851 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29853 this.iconEl.on('click', this.onClick, this);
29856 onClick : function(e)
29858 e.preventDefault();
29864 if(this.fireEvent('click', this, e) === false){
29868 this.parent().setActiveItem(this);
29871 isActive: function ()
29873 return this.active;
29876 setActive : function(state)
29878 if(this.active == state){
29882 this.active = state;
29885 this.el.addClass('active');
29889 this.el.removeClass('active');
29894 setDisabled : function(state)
29896 if(this.disabled == state){
29900 this.disabled = state;
29903 this.el.addClass('disabled');
29907 this.el.removeClass('disabled');
29910 tooltipEl : function()
29912 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29925 * @class Roo.bootstrap.FieldLabel
29926 * @extends Roo.bootstrap.Component
29927 * Bootstrap FieldLabel class
29928 * @cfg {String} html contents of the element
29929 * @cfg {String} tag tag of the element default label
29930 * @cfg {String} cls class of the element
29931 * @cfg {String} target label target
29932 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29933 * @cfg {String} invalidClass default "text-warning"
29934 * @cfg {String} validClass default "text-success"
29935 * @cfg {String} iconTooltip default "This field is required"
29936 * @cfg {String} indicatorpos (left|right) default left
29939 * Create a new FieldLabel
29940 * @param {Object} config The config object
29943 Roo.bootstrap.FieldLabel = function(config){
29944 Roo.bootstrap.Element.superclass.constructor.call(this, config);
29949 * Fires after the field has been marked as invalid.
29950 * @param {Roo.form.FieldLabel} this
29951 * @param {String} msg The validation message
29956 * Fires after the field has been validated with no errors.
29957 * @param {Roo.form.FieldLabel} this
29963 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
29970 invalidClass : 'has-warning',
29971 validClass : 'has-success',
29972 iconTooltip : 'This field is required',
29973 indicatorpos : 'left',
29975 getAutoCreate : function(){
29979 cls : 'roo-bootstrap-field-label ' + this.cls,
29984 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
29985 tooltip : this.iconTooltip
29994 if(this.indicatorpos == 'right'){
29997 cls : 'roo-bootstrap-field-label ' + this.cls,
30006 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
30007 tooltip : this.iconTooltip
30016 initEvents: function()
30018 Roo.bootstrap.Element.superclass.initEvents.call(this);
30020 this.indicator = this.indicatorEl();
30022 if(this.indicator){
30023 this.indicator.removeClass('visible');
30024 this.indicator.addClass('invisible');
30027 Roo.bootstrap.FieldLabel.register(this);
30030 indicatorEl : function()
30032 var indicator = this.el.select('i.roo-required-indicator',true).first();
30043 * Mark this field as valid
30045 markValid : function()
30047 if(this.indicator){
30048 this.indicator.removeClass('visible');
30049 this.indicator.addClass('invisible');
30052 this.el.removeClass(this.invalidClass);
30054 this.el.addClass(this.validClass);
30056 this.fireEvent('valid', this);
30060 * Mark this field as invalid
30061 * @param {String} msg The validation message
30063 markInvalid : function(msg)
30065 if(this.indicator){
30066 this.indicator.removeClass('invisible');
30067 this.indicator.addClass('visible');
30070 this.el.removeClass(this.validClass);
30072 this.el.addClass(this.invalidClass);
30074 this.fireEvent('invalid', this, msg);
30080 Roo.apply(Roo.bootstrap.FieldLabel, {
30085 * register a FieldLabel Group
30086 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30088 register : function(label)
30090 if(this.groups.hasOwnProperty(label.target)){
30094 this.groups[label.target] = label;
30098 * fetch a FieldLabel Group based on the target
30099 * @param {string} target
30100 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30102 get: function(target) {
30103 if (typeof(this.groups[target]) == 'undefined') {
30107 return this.groups[target] ;
30116 * page DateSplitField.
30122 * @class Roo.bootstrap.DateSplitField
30123 * @extends Roo.bootstrap.Component
30124 * Bootstrap DateSplitField class
30125 * @cfg {string} fieldLabel - the label associated
30126 * @cfg {Number} labelWidth set the width of label (0-12)
30127 * @cfg {String} labelAlign (top|left)
30128 * @cfg {Boolean} dayAllowBlank (true|false) default false
30129 * @cfg {Boolean} monthAllowBlank (true|false) default false
30130 * @cfg {Boolean} yearAllowBlank (true|false) default false
30131 * @cfg {string} dayPlaceholder
30132 * @cfg {string} monthPlaceholder
30133 * @cfg {string} yearPlaceholder
30134 * @cfg {string} dayFormat default 'd'
30135 * @cfg {string} monthFormat default 'm'
30136 * @cfg {string} yearFormat default 'Y'
30137 * @cfg {Number} labellg set the width of label (1-12)
30138 * @cfg {Number} labelmd set the width of label (1-12)
30139 * @cfg {Number} labelsm set the width of label (1-12)
30140 * @cfg {Number} labelxs set the width of label (1-12)
30144 * Create a new DateSplitField
30145 * @param {Object} config The config object
30148 Roo.bootstrap.DateSplitField = function(config){
30149 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30155 * getting the data of years
30156 * @param {Roo.bootstrap.DateSplitField} this
30157 * @param {Object} years
30162 * getting the data of days
30163 * @param {Roo.bootstrap.DateSplitField} this
30164 * @param {Object} days
30169 * Fires after the field has been marked as invalid.
30170 * @param {Roo.form.Field} this
30171 * @param {String} msg The validation message
30176 * Fires after the field has been validated with no errors.
30177 * @param {Roo.form.Field} this
30183 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30186 labelAlign : 'top',
30188 dayAllowBlank : false,
30189 monthAllowBlank : false,
30190 yearAllowBlank : false,
30191 dayPlaceholder : '',
30192 monthPlaceholder : '',
30193 yearPlaceholder : '',
30197 isFormField : true,
30203 getAutoCreate : function()
30207 cls : 'row roo-date-split-field-group',
30212 cls : 'form-hidden-field roo-date-split-field-group-value',
30218 var labelCls = 'col-md-12';
30219 var contentCls = 'col-md-4';
30221 if(this.fieldLabel){
30225 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30229 html : this.fieldLabel
30234 if(this.labelAlign == 'left'){
30236 if(this.labelWidth > 12){
30237 label.style = "width: " + this.labelWidth + 'px';
30240 if(this.labelWidth < 13 && this.labelmd == 0){
30241 this.labelmd = this.labelWidth;
30244 if(this.labellg > 0){
30245 labelCls = ' col-lg-' + this.labellg;
30246 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30249 if(this.labelmd > 0){
30250 labelCls = ' col-md-' + this.labelmd;
30251 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30254 if(this.labelsm > 0){
30255 labelCls = ' col-sm-' + this.labelsm;
30256 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30259 if(this.labelxs > 0){
30260 labelCls = ' col-xs-' + this.labelxs;
30261 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30265 label.cls += ' ' + labelCls;
30267 cfg.cn.push(label);
30270 Roo.each(['day', 'month', 'year'], function(t){
30273 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30280 inputEl: function ()
30282 return this.el.select('.roo-date-split-field-group-value', true).first();
30285 onRender : function(ct, position)
30289 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30291 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30293 this.dayField = new Roo.bootstrap.ComboBox({
30294 allowBlank : this.dayAllowBlank,
30295 alwaysQuery : true,
30296 displayField : 'value',
30299 forceSelection : true,
30301 placeholder : this.dayPlaceholder,
30302 selectOnFocus : true,
30303 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30304 triggerAction : 'all',
30306 valueField : 'value',
30307 store : new Roo.data.SimpleStore({
30308 data : (function() {
30310 _this.fireEvent('days', _this, days);
30313 fields : [ 'value' ]
30316 select : function (_self, record, index)
30318 _this.setValue(_this.getValue());
30323 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30325 this.monthField = new Roo.bootstrap.MonthField({
30326 after : '<i class=\"fa fa-calendar\"></i>',
30327 allowBlank : this.monthAllowBlank,
30328 placeholder : this.monthPlaceholder,
30331 render : function (_self)
30333 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30334 e.preventDefault();
30338 select : function (_self, oldvalue, newvalue)
30340 _this.setValue(_this.getValue());
30345 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30347 this.yearField = new Roo.bootstrap.ComboBox({
30348 allowBlank : this.yearAllowBlank,
30349 alwaysQuery : true,
30350 displayField : 'value',
30353 forceSelection : true,
30355 placeholder : this.yearPlaceholder,
30356 selectOnFocus : true,
30357 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30358 triggerAction : 'all',
30360 valueField : 'value',
30361 store : new Roo.data.SimpleStore({
30362 data : (function() {
30364 _this.fireEvent('years', _this, years);
30367 fields : [ 'value' ]
30370 select : function (_self, record, index)
30372 _this.setValue(_this.getValue());
30377 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30380 setValue : function(v, format)
30382 this.inputEl.dom.value = v;
30384 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30386 var d = Date.parseDate(v, f);
30393 this.setDay(d.format(this.dayFormat));
30394 this.setMonth(d.format(this.monthFormat));
30395 this.setYear(d.format(this.yearFormat));
30402 setDay : function(v)
30404 this.dayField.setValue(v);
30405 this.inputEl.dom.value = this.getValue();
30410 setMonth : function(v)
30412 this.monthField.setValue(v, true);
30413 this.inputEl.dom.value = this.getValue();
30418 setYear : function(v)
30420 this.yearField.setValue(v);
30421 this.inputEl.dom.value = this.getValue();
30426 getDay : function()
30428 return this.dayField.getValue();
30431 getMonth : function()
30433 return this.monthField.getValue();
30436 getYear : function()
30438 return this.yearField.getValue();
30441 getValue : function()
30443 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30445 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30455 this.inputEl.dom.value = '';
30460 validate : function()
30462 var d = this.dayField.validate();
30463 var m = this.monthField.validate();
30464 var y = this.yearField.validate();
30469 (!this.dayAllowBlank && !d) ||
30470 (!this.monthAllowBlank && !m) ||
30471 (!this.yearAllowBlank && !y)
30476 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30485 this.markInvalid();
30490 markValid : function()
30493 var label = this.el.select('label', true).first();
30494 var icon = this.el.select('i.fa-star', true).first();
30500 this.fireEvent('valid', this);
30504 * Mark this field as invalid
30505 * @param {String} msg The validation message
30507 markInvalid : function(msg)
30510 var label = this.el.select('label', true).first();
30511 var icon = this.el.select('i.fa-star', true).first();
30513 if(label && !icon){
30514 this.el.select('.roo-date-split-field-label', true).createChild({
30516 cls : 'text-danger fa fa-lg fa-star',
30517 tooltip : 'This field is required',
30518 style : 'margin-right:5px;'
30522 this.fireEvent('invalid', this, msg);
30525 clearInvalid : function()
30527 var label = this.el.select('label', true).first();
30528 var icon = this.el.select('i.fa-star', true).first();
30534 this.fireEvent('valid', this);
30537 getName: function()
30547 * http://masonry.desandro.com
30549 * The idea is to render all the bricks based on vertical width...
30551 * The original code extends 'outlayer' - we might need to use that....
30557 * @class Roo.bootstrap.LayoutMasonry
30558 * @extends Roo.bootstrap.Component
30559 * Bootstrap Layout Masonry class
30562 * Create a new Element
30563 * @param {Object} config The config object
30566 Roo.bootstrap.LayoutMasonry = function(config){
30568 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30572 Roo.bootstrap.LayoutMasonry.register(this);
30578 * Fire after layout the items
30579 * @param {Roo.bootstrap.LayoutMasonry} this
30580 * @param {Roo.EventObject} e
30587 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30590 * @cfg {Boolean} isLayoutInstant = no animation?
30592 isLayoutInstant : false, // needed?
30595 * @cfg {Number} boxWidth width of the columns
30600 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30605 * @cfg {Number} padWidth padding below box..
30610 * @cfg {Number} gutter gutter width..
30615 * @cfg {Number} maxCols maximum number of columns
30621 * @cfg {Boolean} isAutoInitial defalut true
30623 isAutoInitial : true,
30628 * @cfg {Boolean} isHorizontal defalut false
30630 isHorizontal : false,
30632 currentSize : null,
30638 bricks: null, //CompositeElement
30642 _isLayoutInited : false,
30644 // isAlternative : false, // only use for vertical layout...
30647 * @cfg {Number} alternativePadWidth padding below box..
30649 alternativePadWidth : 50,
30651 selectedBrick : [],
30653 getAutoCreate : function(){
30655 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30659 cls: 'blog-masonary-wrapper ' + this.cls,
30661 cls : 'mas-boxes masonary'
30668 getChildContainer: function( )
30670 if (this.boxesEl) {
30671 return this.boxesEl;
30674 this.boxesEl = this.el.select('.mas-boxes').first();
30676 return this.boxesEl;
30680 initEvents : function()
30684 if(this.isAutoInitial){
30685 Roo.log('hook children rendered');
30686 this.on('childrenrendered', function() {
30687 Roo.log('children rendered');
30693 initial : function()
30695 this.selectedBrick = [];
30697 this.currentSize = this.el.getBox(true);
30699 Roo.EventManager.onWindowResize(this.resize, this);
30701 if(!this.isAutoInitial){
30709 //this.layout.defer(500,this);
30713 resize : function()
30715 var cs = this.el.getBox(true);
30718 this.currentSize.width == cs.width &&
30719 this.currentSize.x == cs.x &&
30720 this.currentSize.height == cs.height &&
30721 this.currentSize.y == cs.y
30723 Roo.log("no change in with or X or Y");
30727 this.currentSize = cs;
30733 layout : function()
30735 this._resetLayout();
30737 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30739 this.layoutItems( isInstant );
30741 this._isLayoutInited = true;
30743 this.fireEvent('layout', this);
30747 _resetLayout : function()
30749 if(this.isHorizontal){
30750 this.horizontalMeasureColumns();
30754 this.verticalMeasureColumns();
30758 verticalMeasureColumns : function()
30760 this.getContainerWidth();
30762 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30763 // this.colWidth = Math.floor(this.containerWidth * 0.8);
30767 var boxWidth = this.boxWidth + this.padWidth;
30769 if(this.containerWidth < this.boxWidth){
30770 boxWidth = this.containerWidth
30773 var containerWidth = this.containerWidth;
30775 var cols = Math.floor(containerWidth / boxWidth);
30777 this.cols = Math.max( cols, 1 );
30779 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30781 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30783 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30785 this.colWidth = boxWidth + avail - this.padWidth;
30787 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30788 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
30791 horizontalMeasureColumns : function()
30793 this.getContainerWidth();
30795 var boxWidth = this.boxWidth;
30797 if(this.containerWidth < boxWidth){
30798 boxWidth = this.containerWidth;
30801 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30803 this.el.setHeight(boxWidth);
30807 getContainerWidth : function()
30809 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
30812 layoutItems : function( isInstant )
30814 Roo.log(this.bricks);
30816 var items = Roo.apply([], this.bricks);
30818 if(this.isHorizontal){
30819 this._horizontalLayoutItems( items , isInstant );
30823 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30824 // this._verticalAlternativeLayoutItems( items , isInstant );
30828 this._verticalLayoutItems( items , isInstant );
30832 _verticalLayoutItems : function ( items , isInstant)
30834 if ( !items || !items.length ) {
30839 ['xs', 'xs', 'xs', 'tall'],
30840 ['xs', 'xs', 'tall'],
30841 ['xs', 'xs', 'sm'],
30842 ['xs', 'xs', 'xs'],
30848 ['sm', 'xs', 'xs'],
30852 ['tall', 'xs', 'xs', 'xs'],
30853 ['tall', 'xs', 'xs'],
30865 Roo.each(items, function(item, k){
30867 switch (item.size) {
30868 // these layouts take up a full box,
30879 boxes.push([item]);
30902 var filterPattern = function(box, length)
30910 var pattern = box.slice(0, length);
30914 Roo.each(pattern, function(i){
30915 format.push(i.size);
30918 Roo.each(standard, function(s){
30920 if(String(s) != String(format)){
30929 if(!match && length == 1){
30934 filterPattern(box, length - 1);
30938 queue.push(pattern);
30940 box = box.slice(length, box.length);
30942 filterPattern(box, 4);
30948 Roo.each(boxes, function(box, k){
30954 if(box.length == 1){
30959 filterPattern(box, 4);
30963 this._processVerticalLayoutQueue( queue, isInstant );
30967 // _verticalAlternativeLayoutItems : function( items , isInstant )
30969 // if ( !items || !items.length ) {
30973 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
30977 _horizontalLayoutItems : function ( items , isInstant)
30979 if ( !items || !items.length || items.length < 3) {
30985 var eItems = items.slice(0, 3);
30987 items = items.slice(3, items.length);
30990 ['xs', 'xs', 'xs', 'wide'],
30991 ['xs', 'xs', 'wide'],
30992 ['xs', 'xs', 'sm'],
30993 ['xs', 'xs', 'xs'],
30999 ['sm', 'xs', 'xs'],
31003 ['wide', 'xs', 'xs', 'xs'],
31004 ['wide', 'xs', 'xs'],
31017 Roo.each(items, function(item, k){
31019 switch (item.size) {
31030 boxes.push([item]);
31054 var filterPattern = function(box, length)
31062 var pattern = box.slice(0, length);
31066 Roo.each(pattern, function(i){
31067 format.push(i.size);
31070 Roo.each(standard, function(s){
31072 if(String(s) != String(format)){
31081 if(!match && length == 1){
31086 filterPattern(box, length - 1);
31090 queue.push(pattern);
31092 box = box.slice(length, box.length);
31094 filterPattern(box, 4);
31100 Roo.each(boxes, function(box, k){
31106 if(box.length == 1){
31111 filterPattern(box, 4);
31118 var pos = this.el.getBox(true);
31122 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31124 var hit_end = false;
31126 Roo.each(queue, function(box){
31130 Roo.each(box, function(b){
31132 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31142 Roo.each(box, function(b){
31144 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31147 mx = Math.max(mx, b.x);
31151 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31155 Roo.each(box, function(b){
31157 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31171 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31174 /** Sets position of item in DOM
31175 * @param {Element} item
31176 * @param {Number} x - horizontal position
31177 * @param {Number} y - vertical position
31178 * @param {Boolean} isInstant - disables transitions
31180 _processVerticalLayoutQueue : function( queue, isInstant )
31182 var pos = this.el.getBox(true);
31187 for (var i = 0; i < this.cols; i++){
31191 Roo.each(queue, function(box, k){
31193 var col = k % this.cols;
31195 Roo.each(box, function(b,kk){
31197 b.el.position('absolute');
31199 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31200 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31202 if(b.size == 'md-left' || b.size == 'md-right'){
31203 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31204 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31207 b.el.setWidth(width);
31208 b.el.setHeight(height);
31210 b.el.select('iframe',true).setSize(width,height);
31214 for (var i = 0; i < this.cols; i++){
31216 if(maxY[i] < maxY[col]){
31221 col = Math.min(col, i);
31225 x = pos.x + col * (this.colWidth + this.padWidth);
31229 var positions = [];
31231 switch (box.length){
31233 positions = this.getVerticalOneBoxColPositions(x, y, box);
31236 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31239 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31242 positions = this.getVerticalFourBoxColPositions(x, y, box);
31248 Roo.each(box, function(b,kk){
31250 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31252 var sz = b.el.getSize();
31254 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31262 for (var i = 0; i < this.cols; i++){
31263 mY = Math.max(mY, maxY[i]);
31266 this.el.setHeight(mY - pos.y);
31270 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31272 // var pos = this.el.getBox(true);
31275 // var maxX = pos.right;
31277 // var maxHeight = 0;
31279 // Roo.each(items, function(item, k){
31283 // item.el.position('absolute');
31285 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31287 // item.el.setWidth(width);
31289 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31291 // item.el.setHeight(height);
31294 // item.el.setXY([x, y], isInstant ? false : true);
31296 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31299 // y = y + height + this.alternativePadWidth;
31301 // maxHeight = maxHeight + height + this.alternativePadWidth;
31305 // this.el.setHeight(maxHeight);
31309 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31311 var pos = this.el.getBox(true);
31316 var maxX = pos.right;
31318 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31320 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31322 Roo.each(queue, function(box, k){
31324 Roo.each(box, function(b, kk){
31326 b.el.position('absolute');
31328 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31329 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31331 if(b.size == 'md-left' || b.size == 'md-right'){
31332 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31333 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31336 b.el.setWidth(width);
31337 b.el.setHeight(height);
31345 var positions = [];
31347 switch (box.length){
31349 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31352 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31355 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31358 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31364 Roo.each(box, function(b,kk){
31366 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31368 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31376 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31378 Roo.each(eItems, function(b,k){
31380 b.size = (k == 0) ? 'sm' : 'xs';
31381 b.x = (k == 0) ? 2 : 1;
31382 b.y = (k == 0) ? 2 : 1;
31384 b.el.position('absolute');
31386 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31388 b.el.setWidth(width);
31390 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31392 b.el.setHeight(height);
31396 var positions = [];
31399 x : maxX - this.unitWidth * 2 - this.gutter,
31404 x : maxX - this.unitWidth,
31405 y : minY + (this.unitWidth + this.gutter) * 2
31409 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31413 Roo.each(eItems, function(b,k){
31415 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31421 getVerticalOneBoxColPositions : function(x, y, box)
31425 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31427 if(box[0].size == 'md-left'){
31431 if(box[0].size == 'md-right'){
31436 x : x + (this.unitWidth + this.gutter) * rand,
31443 getVerticalTwoBoxColPositions : function(x, y, box)
31447 if(box[0].size == 'xs'){
31451 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31455 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31469 x : x + (this.unitWidth + this.gutter) * 2,
31470 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31477 getVerticalThreeBoxColPositions : function(x, y, box)
31481 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31489 x : x + (this.unitWidth + this.gutter) * 1,
31494 x : x + (this.unitWidth + this.gutter) * 2,
31502 if(box[0].size == 'xs' && box[1].size == 'xs'){
31511 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31515 x : x + (this.unitWidth + this.gutter) * 1,
31529 x : x + (this.unitWidth + this.gutter) * 2,
31534 x : x + (this.unitWidth + this.gutter) * 2,
31535 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31542 getVerticalFourBoxColPositions : function(x, y, box)
31546 if(box[0].size == 'xs'){
31555 y : y + (this.unitHeight + this.gutter) * 1
31560 y : y + (this.unitHeight + this.gutter) * 2
31564 x : x + (this.unitWidth + this.gutter) * 1,
31578 x : x + (this.unitWidth + this.gutter) * 2,
31583 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31584 y : y + (this.unitHeight + this.gutter) * 1
31588 x : x + (this.unitWidth + this.gutter) * 2,
31589 y : y + (this.unitWidth + this.gutter) * 2
31596 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31600 if(box[0].size == 'md-left'){
31602 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31609 if(box[0].size == 'md-right'){
31611 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31612 y : minY + (this.unitWidth + this.gutter) * 1
31618 var rand = Math.floor(Math.random() * (4 - box[0].y));
31621 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31622 y : minY + (this.unitWidth + this.gutter) * rand
31629 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31633 if(box[0].size == 'xs'){
31636 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31641 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31642 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31650 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31655 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31656 y : minY + (this.unitWidth + this.gutter) * 2
31663 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31667 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31670 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31675 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31676 y : minY + (this.unitWidth + this.gutter) * 1
31680 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31681 y : minY + (this.unitWidth + this.gutter) * 2
31688 if(box[0].size == 'xs' && box[1].size == 'xs'){
31691 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31696 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31701 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31702 y : minY + (this.unitWidth + this.gutter) * 1
31710 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31715 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31716 y : minY + (this.unitWidth + this.gutter) * 2
31720 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31721 y : minY + (this.unitWidth + this.gutter) * 2
31728 getHorizontalFourBoxColPositions : function(maxX, minY, box)
31732 if(box[0].size == 'xs'){
31735 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31740 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31745 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),
31750 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31751 y : minY + (this.unitWidth + this.gutter) * 1
31759 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31764 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31765 y : minY + (this.unitWidth + this.gutter) * 2
31769 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31770 y : minY + (this.unitWidth + this.gutter) * 2
31774 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),
31775 y : minY + (this.unitWidth + this.gutter) * 2
31783 * remove a Masonry Brick
31784 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31786 removeBrick : function(brick_id)
31792 for (var i = 0; i<this.bricks.length; i++) {
31793 if (this.bricks[i].id == brick_id) {
31794 this.bricks.splice(i,1);
31795 this.el.dom.removeChild(Roo.get(brick_id).dom);
31802 * adds a Masonry Brick
31803 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31805 addBrick : function(cfg)
31807 var cn = new Roo.bootstrap.MasonryBrick(cfg);
31808 //this.register(cn);
31809 cn.parentId = this.id;
31810 cn.onRender(this.el, null);
31815 * register a Masonry Brick
31816 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31819 register : function(brick)
31821 this.bricks.push(brick);
31822 brick.masonryId = this.id;
31826 * clear all the Masonry Brick
31828 clearAll : function()
31831 //this.getChildContainer().dom.innerHTML = "";
31832 this.el.dom.innerHTML = '';
31835 getSelected : function()
31837 if (!this.selectedBrick) {
31841 return this.selectedBrick;
31845 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31849 * register a Masonry Layout
31850 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31853 register : function(layout)
31855 this.groups[layout.id] = layout;
31858 * fetch a Masonry Layout based on the masonry layout ID
31859 * @param {string} the masonry layout to add
31860 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31863 get: function(layout_id) {
31864 if (typeof(this.groups[layout_id]) == 'undefined') {
31867 return this.groups[layout_id] ;
31879 * http://masonry.desandro.com
31881 * The idea is to render all the bricks based on vertical width...
31883 * The original code extends 'outlayer' - we might need to use that....
31889 * @class Roo.bootstrap.LayoutMasonryAuto
31890 * @extends Roo.bootstrap.Component
31891 * Bootstrap Layout Masonry class
31894 * Create a new Element
31895 * @param {Object} config The config object
31898 Roo.bootstrap.LayoutMasonryAuto = function(config){
31899 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31902 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
31905 * @cfg {Boolean} isFitWidth - resize the width..
31907 isFitWidth : false, // options..
31909 * @cfg {Boolean} isOriginLeft = left align?
31911 isOriginLeft : true,
31913 * @cfg {Boolean} isOriginTop = top align?
31915 isOriginTop : false,
31917 * @cfg {Boolean} isLayoutInstant = no animation?
31919 isLayoutInstant : false, // needed?
31921 * @cfg {Boolean} isResizingContainer = not sure if this is used..
31923 isResizingContainer : true,
31925 * @cfg {Number} columnWidth width of the columns
31931 * @cfg {Number} maxCols maximum number of columns
31936 * @cfg {Number} padHeight padding below box..
31942 * @cfg {Boolean} isAutoInitial defalut true
31945 isAutoInitial : true,
31951 initialColumnWidth : 0,
31952 currentSize : null,
31954 colYs : null, // array.
31961 bricks: null, //CompositeElement
31962 cols : 0, // array?
31963 // element : null, // wrapped now this.el
31964 _isLayoutInited : null,
31967 getAutoCreate : function(){
31971 cls: 'blog-masonary-wrapper ' + this.cls,
31973 cls : 'mas-boxes masonary'
31980 getChildContainer: function( )
31982 if (this.boxesEl) {
31983 return this.boxesEl;
31986 this.boxesEl = this.el.select('.mas-boxes').first();
31988 return this.boxesEl;
31992 initEvents : function()
31996 if(this.isAutoInitial){
31997 Roo.log('hook children rendered');
31998 this.on('childrenrendered', function() {
31999 Roo.log('children rendered');
32006 initial : function()
32008 this.reloadItems();
32010 this.currentSize = this.el.getBox(true);
32012 /// was window resize... - let's see if this works..
32013 Roo.EventManager.onWindowResize(this.resize, this);
32015 if(!this.isAutoInitial){
32020 this.layout.defer(500,this);
32023 reloadItems: function()
32025 this.bricks = this.el.select('.masonry-brick', true);
32027 this.bricks.each(function(b) {
32028 //Roo.log(b.getSize());
32029 if (!b.attr('originalwidth')) {
32030 b.attr('originalwidth', b.getSize().width);
32035 Roo.log(this.bricks.elements.length);
32038 resize : function()
32041 var cs = this.el.getBox(true);
32043 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32044 Roo.log("no change in with or X");
32047 this.currentSize = cs;
32051 layout : function()
32054 this._resetLayout();
32055 //this._manageStamps();
32057 // don't animate first layout
32058 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32059 this.layoutItems( isInstant );
32061 // flag for initalized
32062 this._isLayoutInited = true;
32065 layoutItems : function( isInstant )
32067 //var items = this._getItemsForLayout( this.items );
32068 // original code supports filtering layout items.. we just ignore it..
32070 this._layoutItems( this.bricks , isInstant );
32072 this._postLayout();
32074 _layoutItems : function ( items , isInstant)
32076 //this.fireEvent( 'layout', this, items );
32079 if ( !items || !items.elements.length ) {
32080 // no items, emit event with empty array
32085 items.each(function(item) {
32086 Roo.log("layout item");
32088 // get x/y object from method
32089 var position = this._getItemLayoutPosition( item );
32091 position.item = item;
32092 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32093 queue.push( position );
32096 this._processLayoutQueue( queue );
32098 /** Sets position of item in DOM
32099 * @param {Element} item
32100 * @param {Number} x - horizontal position
32101 * @param {Number} y - vertical position
32102 * @param {Boolean} isInstant - disables transitions
32104 _processLayoutQueue : function( queue )
32106 for ( var i=0, len = queue.length; i < len; i++ ) {
32107 var obj = queue[i];
32108 obj.item.position('absolute');
32109 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32115 * Any logic you want to do after each layout,
32116 * i.e. size the container
32118 _postLayout : function()
32120 this.resizeContainer();
32123 resizeContainer : function()
32125 if ( !this.isResizingContainer ) {
32128 var size = this._getContainerSize();
32130 this.el.setSize(size.width,size.height);
32131 this.boxesEl.setSize(size.width,size.height);
32137 _resetLayout : function()
32139 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32140 this.colWidth = this.el.getWidth();
32141 //this.gutter = this.el.getWidth();
32143 this.measureColumns();
32149 this.colYs.push( 0 );
32155 measureColumns : function()
32157 this.getContainerWidth();
32158 // if columnWidth is 0, default to outerWidth of first item
32159 if ( !this.columnWidth ) {
32160 var firstItem = this.bricks.first();
32161 Roo.log(firstItem);
32162 this.columnWidth = this.containerWidth;
32163 if (firstItem && firstItem.attr('originalwidth') ) {
32164 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32166 // columnWidth fall back to item of first element
32167 Roo.log("set column width?");
32168 this.initialColumnWidth = this.columnWidth ;
32170 // if first elem has no width, default to size of container
32175 if (this.initialColumnWidth) {
32176 this.columnWidth = this.initialColumnWidth;
32181 // column width is fixed at the top - however if container width get's smaller we should
32184 // this bit calcs how man columns..
32186 var columnWidth = this.columnWidth += this.gutter;
32188 // calculate columns
32189 var containerWidth = this.containerWidth + this.gutter;
32191 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32192 // fix rounding errors, typically with gutters
32193 var excess = columnWidth - containerWidth % columnWidth;
32196 // if overshoot is less than a pixel, round up, otherwise floor it
32197 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32198 cols = Math[ mathMethod ]( cols );
32199 this.cols = Math.max( cols, 1 );
32200 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32202 // padding positioning..
32203 var totalColWidth = this.cols * this.columnWidth;
32204 var padavail = this.containerWidth - totalColWidth;
32205 // so for 2 columns - we need 3 'pads'
32207 var padNeeded = (1+this.cols) * this.padWidth;
32209 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32211 this.columnWidth += padExtra
32212 //this.padWidth = Math.floor(padavail / ( this.cols));
32214 // adjust colum width so that padding is fixed??
32216 // we have 3 columns ... total = width * 3
32217 // we have X left over... that should be used by
32219 //if (this.expandC) {
32227 getContainerWidth : function()
32229 /* // container is parent if fit width
32230 var container = this.isFitWidth ? this.element.parentNode : this.element;
32231 // check that this.size and size are there
32232 // IE8 triggers resize on body size change, so they might not be
32234 var size = getSize( container ); //FIXME
32235 this.containerWidth = size && size.innerWidth; //FIXME
32238 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32242 _getItemLayoutPosition : function( item ) // what is item?
32244 // we resize the item to our columnWidth..
32246 item.setWidth(this.columnWidth);
32247 item.autoBoxAdjust = false;
32249 var sz = item.getSize();
32251 // how many columns does this brick span
32252 var remainder = this.containerWidth % this.columnWidth;
32254 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32255 // round if off by 1 pixel, otherwise use ceil
32256 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32257 colSpan = Math.min( colSpan, this.cols );
32259 // normally this should be '1' as we dont' currently allow multi width columns..
32261 var colGroup = this._getColGroup( colSpan );
32262 // get the minimum Y value from the columns
32263 var minimumY = Math.min.apply( Math, colGroup );
32264 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32266 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32268 // position the brick
32270 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32271 y: this.currentSize.y + minimumY + this.padHeight
32275 // apply setHeight to necessary columns
32276 var setHeight = minimumY + sz.height + this.padHeight;
32277 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32279 var setSpan = this.cols + 1 - colGroup.length;
32280 for ( var i = 0; i < setSpan; i++ ) {
32281 this.colYs[ shortColIndex + i ] = setHeight ;
32288 * @param {Number} colSpan - number of columns the element spans
32289 * @returns {Array} colGroup
32291 _getColGroup : function( colSpan )
32293 if ( colSpan < 2 ) {
32294 // if brick spans only one column, use all the column Ys
32299 // how many different places could this brick fit horizontally
32300 var groupCount = this.cols + 1 - colSpan;
32301 // for each group potential horizontal position
32302 for ( var i = 0; i < groupCount; i++ ) {
32303 // make an array of colY values for that one group
32304 var groupColYs = this.colYs.slice( i, i + colSpan );
32305 // and get the max value of the array
32306 colGroup[i] = Math.max.apply( Math, groupColYs );
32311 _manageStamp : function( stamp )
32313 var stampSize = stamp.getSize();
32314 var offset = stamp.getBox();
32315 // get the columns that this stamp affects
32316 var firstX = this.isOriginLeft ? offset.x : offset.right;
32317 var lastX = firstX + stampSize.width;
32318 var firstCol = Math.floor( firstX / this.columnWidth );
32319 firstCol = Math.max( 0, firstCol );
32321 var lastCol = Math.floor( lastX / this.columnWidth );
32322 // lastCol should not go over if multiple of columnWidth #425
32323 lastCol -= lastX % this.columnWidth ? 0 : 1;
32324 lastCol = Math.min( this.cols - 1, lastCol );
32326 // set colYs to bottom of the stamp
32327 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32330 for ( var i = firstCol; i <= lastCol; i++ ) {
32331 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32336 _getContainerSize : function()
32338 this.maxY = Math.max.apply( Math, this.colYs );
32343 if ( this.isFitWidth ) {
32344 size.width = this._getContainerFitWidth();
32350 _getContainerFitWidth : function()
32352 var unusedCols = 0;
32353 // count unused columns
32356 if ( this.colYs[i] !== 0 ) {
32361 // fit container to columns that have been used
32362 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32365 needsResizeLayout : function()
32367 var previousWidth = this.containerWidth;
32368 this.getContainerWidth();
32369 return previousWidth !== this.containerWidth;
32384 * @class Roo.bootstrap.MasonryBrick
32385 * @extends Roo.bootstrap.Component
32386 * Bootstrap MasonryBrick class
32389 * Create a new MasonryBrick
32390 * @param {Object} config The config object
32393 Roo.bootstrap.MasonryBrick = function(config){
32395 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32397 Roo.bootstrap.MasonryBrick.register(this);
32403 * When a MasonryBrick is clcik
32404 * @param {Roo.bootstrap.MasonryBrick} this
32405 * @param {Roo.EventObject} e
32411 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32414 * @cfg {String} title
32418 * @cfg {String} html
32422 * @cfg {String} bgimage
32426 * @cfg {String} videourl
32430 * @cfg {String} cls
32434 * @cfg {String} href
32438 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32443 * @cfg {String} placetitle (center|bottom)
32448 * @cfg {Boolean} isFitContainer defalut true
32450 isFitContainer : true,
32453 * @cfg {Boolean} preventDefault defalut false
32455 preventDefault : false,
32458 * @cfg {Boolean} inverse defalut false
32460 maskInverse : false,
32462 getAutoCreate : function()
32464 if(!this.isFitContainer){
32465 return this.getSplitAutoCreate();
32468 var cls = 'masonry-brick masonry-brick-full';
32470 if(this.href.length){
32471 cls += ' masonry-brick-link';
32474 if(this.bgimage.length){
32475 cls += ' masonry-brick-image';
32478 if(this.maskInverse){
32479 cls += ' mask-inverse';
32482 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32483 cls += ' enable-mask';
32487 cls += ' masonry-' + this.size + '-brick';
32490 if(this.placetitle.length){
32492 switch (this.placetitle) {
32494 cls += ' masonry-center-title';
32497 cls += ' masonry-bottom-title';
32504 if(!this.html.length && !this.bgimage.length){
32505 cls += ' masonry-center-title';
32508 if(!this.html.length && this.bgimage.length){
32509 cls += ' masonry-bottom-title';
32514 cls += ' ' + this.cls;
32518 tag: (this.href.length) ? 'a' : 'div',
32523 cls: 'masonry-brick-mask'
32527 cls: 'masonry-brick-paragraph',
32533 if(this.href.length){
32534 cfg.href = this.href;
32537 var cn = cfg.cn[1].cn;
32539 if(this.title.length){
32542 cls: 'masonry-brick-title',
32547 if(this.html.length){
32550 cls: 'masonry-brick-text',
32555 if (!this.title.length && !this.html.length) {
32556 cfg.cn[1].cls += ' hide';
32559 if(this.bgimage.length){
32562 cls: 'masonry-brick-image-view',
32567 if(this.videourl.length){
32568 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32569 // youtube support only?
32572 cls: 'masonry-brick-image-view',
32575 allowfullscreen : true
32583 getSplitAutoCreate : function()
32585 var cls = 'masonry-brick masonry-brick-split';
32587 if(this.href.length){
32588 cls += ' masonry-brick-link';
32591 if(this.bgimage.length){
32592 cls += ' masonry-brick-image';
32596 cls += ' masonry-' + this.size + '-brick';
32599 switch (this.placetitle) {
32601 cls += ' masonry-center-title';
32604 cls += ' masonry-bottom-title';
32607 if(!this.bgimage.length){
32608 cls += ' masonry-center-title';
32611 if(this.bgimage.length){
32612 cls += ' masonry-bottom-title';
32618 cls += ' ' + this.cls;
32622 tag: (this.href.length) ? 'a' : 'div',
32627 cls: 'masonry-brick-split-head',
32631 cls: 'masonry-brick-paragraph',
32638 cls: 'masonry-brick-split-body',
32644 if(this.href.length){
32645 cfg.href = this.href;
32648 if(this.title.length){
32649 cfg.cn[0].cn[0].cn.push({
32651 cls: 'masonry-brick-title',
32656 if(this.html.length){
32657 cfg.cn[1].cn.push({
32659 cls: 'masonry-brick-text',
32664 if(this.bgimage.length){
32665 cfg.cn[0].cn.push({
32667 cls: 'masonry-brick-image-view',
32672 if(this.videourl.length){
32673 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32674 // youtube support only?
32675 cfg.cn[0].cn.cn.push({
32677 cls: 'masonry-brick-image-view',
32680 allowfullscreen : true
32687 initEvents: function()
32689 switch (this.size) {
32722 this.el.on('touchstart', this.onTouchStart, this);
32723 this.el.on('touchmove', this.onTouchMove, this);
32724 this.el.on('touchend', this.onTouchEnd, this);
32725 this.el.on('contextmenu', this.onContextMenu, this);
32727 this.el.on('mouseenter' ,this.enter, this);
32728 this.el.on('mouseleave', this.leave, this);
32729 this.el.on('click', this.onClick, this);
32732 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32733 this.parent().bricks.push(this);
32738 onClick: function(e, el)
32740 var time = this.endTimer - this.startTimer;
32741 // Roo.log(e.preventDefault());
32744 e.preventDefault();
32749 if(!this.preventDefault){
32753 e.preventDefault();
32755 if (this.activeClass != '') {
32756 this.selectBrick();
32759 this.fireEvent('click', this, e);
32762 enter: function(e, el)
32764 e.preventDefault();
32766 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32770 if(this.bgimage.length && this.html.length){
32771 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32775 leave: function(e, el)
32777 e.preventDefault();
32779 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32783 if(this.bgimage.length && this.html.length){
32784 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32788 onTouchStart: function(e, el)
32790 // e.preventDefault();
32792 this.touchmoved = false;
32794 if(!this.isFitContainer){
32798 if(!this.bgimage.length || !this.html.length){
32802 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32804 this.timer = new Date().getTime();
32808 onTouchMove: function(e, el)
32810 this.touchmoved = true;
32813 onContextMenu : function(e,el)
32815 e.preventDefault();
32816 e.stopPropagation();
32820 onTouchEnd: function(e, el)
32822 // e.preventDefault();
32824 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32831 if(!this.bgimage.length || !this.html.length){
32833 if(this.href.length){
32834 window.location.href = this.href;
32840 if(!this.isFitContainer){
32844 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32846 window.location.href = this.href;
32849 //selection on single brick only
32850 selectBrick : function() {
32852 if (!this.parentId) {
32856 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32857 var index = m.selectedBrick.indexOf(this.id);
32860 m.selectedBrick.splice(index,1);
32861 this.el.removeClass(this.activeClass);
32865 for(var i = 0; i < m.selectedBrick.length; i++) {
32866 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32867 b.el.removeClass(b.activeClass);
32870 m.selectedBrick = [];
32872 m.selectedBrick.push(this.id);
32873 this.el.addClass(this.activeClass);
32877 isSelected : function(){
32878 return this.el.hasClass(this.activeClass);
32883 Roo.apply(Roo.bootstrap.MasonryBrick, {
32886 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32888 * register a Masonry Brick
32889 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32892 register : function(brick)
32894 //this.groups[brick.id] = brick;
32895 this.groups.add(brick.id, brick);
32898 * fetch a masonry brick based on the masonry brick ID
32899 * @param {string} the masonry brick to add
32900 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32903 get: function(brick_id)
32905 // if (typeof(this.groups[brick_id]) == 'undefined') {
32908 // return this.groups[brick_id] ;
32910 if(this.groups.key(brick_id)) {
32911 return this.groups.key(brick_id);
32929 * @class Roo.bootstrap.Brick
32930 * @extends Roo.bootstrap.Component
32931 * Bootstrap Brick class
32934 * Create a new Brick
32935 * @param {Object} config The config object
32938 Roo.bootstrap.Brick = function(config){
32939 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32945 * When a Brick is click
32946 * @param {Roo.bootstrap.Brick} this
32947 * @param {Roo.EventObject} e
32953 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
32956 * @cfg {String} title
32960 * @cfg {String} html
32964 * @cfg {String} bgimage
32968 * @cfg {String} cls
32972 * @cfg {String} href
32976 * @cfg {String} video
32980 * @cfg {Boolean} square
32984 getAutoCreate : function()
32986 var cls = 'roo-brick';
32988 if(this.href.length){
32989 cls += ' roo-brick-link';
32992 if(this.bgimage.length){
32993 cls += ' roo-brick-image';
32996 if(!this.html.length && !this.bgimage.length){
32997 cls += ' roo-brick-center-title';
33000 if(!this.html.length && this.bgimage.length){
33001 cls += ' roo-brick-bottom-title';
33005 cls += ' ' + this.cls;
33009 tag: (this.href.length) ? 'a' : 'div',
33014 cls: 'roo-brick-paragraph',
33020 if(this.href.length){
33021 cfg.href = this.href;
33024 var cn = cfg.cn[0].cn;
33026 if(this.title.length){
33029 cls: 'roo-brick-title',
33034 if(this.html.length){
33037 cls: 'roo-brick-text',
33044 if(this.bgimage.length){
33047 cls: 'roo-brick-image-view',
33055 initEvents: function()
33057 if(this.title.length || this.html.length){
33058 this.el.on('mouseenter' ,this.enter, this);
33059 this.el.on('mouseleave', this.leave, this);
33062 Roo.EventManager.onWindowResize(this.resize, this);
33064 if(this.bgimage.length){
33065 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33066 this.imageEl.on('load', this.onImageLoad, this);
33073 onImageLoad : function()
33078 resize : function()
33080 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33082 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33084 if(this.bgimage.length){
33085 var image = this.el.select('.roo-brick-image-view', true).first();
33087 image.setWidth(paragraph.getWidth());
33090 image.setHeight(paragraph.getWidth());
33093 this.el.setHeight(image.getHeight());
33094 paragraph.setHeight(image.getHeight());
33100 enter: function(e, el)
33102 e.preventDefault();
33104 if(this.bgimage.length){
33105 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33106 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33110 leave: function(e, el)
33112 e.preventDefault();
33114 if(this.bgimage.length){
33115 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33116 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33131 * @class Roo.bootstrap.NumberField
33132 * @extends Roo.bootstrap.Input
33133 * Bootstrap NumberField class
33139 * Create a new NumberField
33140 * @param {Object} config The config object
33143 Roo.bootstrap.NumberField = function(config){
33144 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33147 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33150 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33152 allowDecimals : true,
33154 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33156 decimalSeparator : ".",
33158 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33160 decimalPrecision : 2,
33162 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33164 allowNegative : true,
33167 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33171 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33173 minValue : Number.NEGATIVE_INFINITY,
33175 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33177 maxValue : Number.MAX_VALUE,
33179 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33181 minText : "The minimum value for this field is {0}",
33183 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33185 maxText : "The maximum value for this field is {0}",
33187 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33188 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33190 nanText : "{0} is not a valid number",
33192 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
33196 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33198 thousandsDelimiter : false,
33200 * @cfg {String} valueAlign alignment of value
33202 valueAlign : "left",
33204 getAutoCreate : function()
33206 var hiddenInput = {
33210 cls: 'hidden-number-input'
33214 hiddenInput.name = this.name;
33219 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33221 this.name = hiddenInput.name;
33223 if(cfg.cn.length > 0) {
33224 cfg.cn.push(hiddenInput);
33231 initEvents : function()
33233 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33235 var allowed = "0123456789";
33237 if(this.allowDecimals){
33238 allowed += this.decimalSeparator;
33241 if(this.allowNegative){
33245 if(this.thousandsDelimiter) {
33249 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33251 var keyPress = function(e){
33253 var k = e.getKey();
33255 var c = e.getCharCode();
33258 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33259 allowed.indexOf(String.fromCharCode(c)) === -1
33265 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33269 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33274 this.el.on("keypress", keyPress, this);
33277 validateValue : function(value)
33280 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33284 var num = this.parseValue(value);
33287 this.markInvalid(String.format(this.nanText, value));
33291 if(num < this.minValue){
33292 this.markInvalid(String.format(this.minText, this.minValue));
33296 if(num > this.maxValue){
33297 this.markInvalid(String.format(this.maxText, this.maxValue));
33304 getValue : function()
33306 var v = this.hiddenEl().getValue();
33308 return this.fixPrecision(this.parseValue(v));
33311 parseValue : function(value)
33313 if(this.thousandsDelimiter) {
33315 r = new RegExp(",", "g");
33316 value = value.replace(r, "");
33319 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33320 return isNaN(value) ? '' : value;
33323 fixPrecision : function(value)
33325 if(this.thousandsDelimiter) {
33327 r = new RegExp(",", "g");
33328 value = value.replace(r, "");
33331 var nan = isNaN(value);
33333 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33334 return nan ? '' : value;
33336 return parseFloat(value).toFixed(this.decimalPrecision);
33339 setValue : function(v)
33341 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33347 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33349 this.inputEl().dom.value = (v == '') ? '' :
33350 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33352 if(!this.allowZero && v === '0') {
33353 this.hiddenEl().dom.value = '';
33354 this.inputEl().dom.value = '';
33361 decimalPrecisionFcn : function(v)
33363 return Math.floor(v);
33366 beforeBlur : function()
33372 var v = this.parseValue(this.getRawValue());
33379 hiddenEl : function()
33381 return this.el.select('input.hidden-number-input',true).first();
33393 * @class Roo.bootstrap.DocumentSlider
33394 * @extends Roo.bootstrap.Component
33395 * Bootstrap DocumentSlider class
33398 * Create a new DocumentViewer
33399 * @param {Object} config The config object
33402 Roo.bootstrap.DocumentSlider = function(config){
33403 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33410 * Fire after initEvent
33411 * @param {Roo.bootstrap.DocumentSlider} this
33416 * Fire after update
33417 * @param {Roo.bootstrap.DocumentSlider} this
33423 * @param {Roo.bootstrap.DocumentSlider} this
33429 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33435 getAutoCreate : function()
33439 cls : 'roo-document-slider',
33443 cls : 'roo-document-slider-header',
33447 cls : 'roo-document-slider-header-title'
33453 cls : 'roo-document-slider-body',
33457 cls : 'roo-document-slider-prev',
33461 cls : 'fa fa-chevron-left'
33467 cls : 'roo-document-slider-thumb',
33471 cls : 'roo-document-slider-image'
33477 cls : 'roo-document-slider-next',
33481 cls : 'fa fa-chevron-right'
33493 initEvents : function()
33495 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33496 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33498 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33499 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33501 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33502 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33504 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33505 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33507 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33508 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33510 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33511 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33513 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33514 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33516 this.thumbEl.on('click', this.onClick, this);
33518 this.prevIndicator.on('click', this.prev, this);
33520 this.nextIndicator.on('click', this.next, this);
33524 initial : function()
33526 if(this.files.length){
33527 this.indicator = 1;
33531 this.fireEvent('initial', this);
33534 update : function()
33536 this.imageEl.attr('src', this.files[this.indicator - 1]);
33538 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33540 this.prevIndicator.show();
33542 if(this.indicator == 1){
33543 this.prevIndicator.hide();
33546 this.nextIndicator.show();
33548 if(this.indicator == this.files.length){
33549 this.nextIndicator.hide();
33552 this.thumbEl.scrollTo('top');
33554 this.fireEvent('update', this);
33557 onClick : function(e)
33559 e.preventDefault();
33561 this.fireEvent('click', this);
33566 e.preventDefault();
33568 this.indicator = Math.max(1, this.indicator - 1);
33575 e.preventDefault();
33577 this.indicator = Math.min(this.files.length, this.indicator + 1);
33591 * @class Roo.bootstrap.RadioSet
33592 * @extends Roo.bootstrap.Input
33593 * Bootstrap RadioSet class
33594 * @cfg {String} indicatorpos (left|right) default left
33595 * @cfg {Boolean} inline (true|false) inline the element (default true)
33596 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33598 * Create a new RadioSet
33599 * @param {Object} config The config object
33602 Roo.bootstrap.RadioSet = function(config){
33604 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33608 Roo.bootstrap.RadioSet.register(this);
33613 * Fires when the element is checked or unchecked.
33614 * @param {Roo.bootstrap.RadioSet} this This radio
33615 * @param {Roo.bootstrap.Radio} item The checked item
33620 * Fires when the element is click.
33621 * @param {Roo.bootstrap.RadioSet} this This radio set
33622 * @param {Roo.bootstrap.Radio} item The checked item
33623 * @param {Roo.EventObject} e The event object
33630 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33638 indicatorpos : 'left',
33640 getAutoCreate : function()
33644 cls : 'roo-radio-set-label',
33648 html : this.fieldLabel
33653 if(this.indicatorpos == 'left'){
33656 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33657 tooltip : 'This field is required'
33662 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33663 tooltip : 'This field is required'
33669 cls : 'roo-radio-set-items'
33672 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33674 if (align === 'left' && this.fieldLabel.length) {
33677 cls : "roo-radio-set-right",
33683 if(this.labelWidth > 12){
33684 label.style = "width: " + this.labelWidth + 'px';
33687 if(this.labelWidth < 13 && this.labelmd == 0){
33688 this.labelmd = this.labelWidth;
33691 if(this.labellg > 0){
33692 label.cls += ' col-lg-' + this.labellg;
33693 items.cls += ' col-lg-' + (12 - this.labellg);
33696 if(this.labelmd > 0){
33697 label.cls += ' col-md-' + this.labelmd;
33698 items.cls += ' col-md-' + (12 - this.labelmd);
33701 if(this.labelsm > 0){
33702 label.cls += ' col-sm-' + this.labelsm;
33703 items.cls += ' col-sm-' + (12 - this.labelsm);
33706 if(this.labelxs > 0){
33707 label.cls += ' col-xs-' + this.labelxs;
33708 items.cls += ' col-xs-' + (12 - this.labelxs);
33714 cls : 'roo-radio-set',
33718 cls : 'roo-radio-set-input',
33721 value : this.value ? this.value : ''
33728 if(this.weight.length){
33729 cfg.cls += ' roo-radio-' + this.weight;
33733 cfg.cls += ' roo-radio-set-inline';
33737 ['xs','sm','md','lg'].map(function(size){
33738 if (settings[size]) {
33739 cfg.cls += ' col-' + size + '-' + settings[size];
33747 initEvents : function()
33749 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33750 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33752 if(!this.fieldLabel.length){
33753 this.labelEl.hide();
33756 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33757 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33759 this.indicator = this.indicatorEl();
33761 if(this.indicator){
33762 this.indicator.addClass('invisible');
33765 this.originalValue = this.getValue();
33769 inputEl: function ()
33771 return this.el.select('.roo-radio-set-input', true).first();
33774 getChildContainer : function()
33776 return this.itemsEl;
33779 register : function(item)
33781 this.radioes.push(item);
33785 validate : function()
33787 if(this.getVisibilityEl().hasClass('hidden')){
33793 Roo.each(this.radioes, function(i){
33802 if(this.allowBlank) {
33806 if(this.disabled || valid){
33811 this.markInvalid();
33816 markValid : function()
33818 if(this.labelEl.isVisible(true)){
33819 this.indicatorEl().removeClass('visible');
33820 this.indicatorEl().addClass('invisible');
33823 this.el.removeClass([this.invalidClass, this.validClass]);
33824 this.el.addClass(this.validClass);
33826 this.fireEvent('valid', this);
33829 markInvalid : function(msg)
33831 if(this.allowBlank || this.disabled){
33835 if(this.labelEl.isVisible(true)){
33836 this.indicatorEl().removeClass('invisible');
33837 this.indicatorEl().addClass('visible');
33840 this.el.removeClass([this.invalidClass, this.validClass]);
33841 this.el.addClass(this.invalidClass);
33843 this.fireEvent('invalid', this, msg);
33847 setValue : function(v, suppressEvent)
33849 if(this.value === v){
33856 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33859 Roo.each(this.radioes, function(i){
33861 i.el.removeClass('checked');
33864 Roo.each(this.radioes, function(i){
33866 if(i.value === v || i.value.toString() === v.toString()){
33868 i.el.addClass('checked');
33870 if(suppressEvent !== true){
33871 this.fireEvent('check', this, i);
33882 clearInvalid : function(){
33884 if(!this.el || this.preventMark){
33888 this.el.removeClass([this.invalidClass]);
33890 this.fireEvent('valid', this);
33895 Roo.apply(Roo.bootstrap.RadioSet, {
33899 register : function(set)
33901 this.groups[set.name] = set;
33904 get: function(name)
33906 if (typeof(this.groups[name]) == 'undefined') {
33910 return this.groups[name] ;
33916 * Ext JS Library 1.1.1
33917 * Copyright(c) 2006-2007, Ext JS, LLC.
33919 * Originally Released Under LGPL - original licence link has changed is not relivant.
33922 * <script type="text/javascript">
33927 * @class Roo.bootstrap.SplitBar
33928 * @extends Roo.util.Observable
33929 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33933 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33934 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33935 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33936 split.minSize = 100;
33937 split.maxSize = 600;
33938 split.animate = true;
33939 split.on('moved', splitterMoved);
33942 * Create a new SplitBar
33943 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
33944 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
33945 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33946 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
33947 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33948 position of the SplitBar).
33950 Roo.bootstrap.SplitBar = function(cfg){
33955 // dragElement : elm
33956 // resizingElement: el,
33958 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33959 // placement : Roo.bootstrap.SplitBar.LEFT ,
33960 // existingProxy ???
33963 this.el = Roo.get(cfg.dragElement, true);
33964 this.el.dom.unselectable = "on";
33966 this.resizingEl = Roo.get(cfg.resizingElement, true);
33970 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33971 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
33974 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
33977 * The minimum size of the resizing element. (Defaults to 0)
33983 * The maximum size of the resizing element. (Defaults to 2000)
33986 this.maxSize = 2000;
33989 * Whether to animate the transition to the new size
33992 this.animate = false;
33995 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
33998 this.useShim = false;
34003 if(!cfg.existingProxy){
34005 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34007 this.proxy = Roo.get(cfg.existingProxy).dom;
34010 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34013 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34016 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34019 this.dragSpecs = {};
34022 * @private The adapter to use to positon and resize elements
34024 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34025 this.adapter.init(this);
34027 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34029 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34030 this.el.addClass("roo-splitbar-h");
34033 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34034 this.el.addClass("roo-splitbar-v");
34040 * Fires when the splitter is moved (alias for {@link #event-moved})
34041 * @param {Roo.bootstrap.SplitBar} this
34042 * @param {Number} newSize the new width or height
34047 * Fires when the splitter is moved
34048 * @param {Roo.bootstrap.SplitBar} this
34049 * @param {Number} newSize the new width or height
34053 * @event beforeresize
34054 * Fires before the splitter is dragged
34055 * @param {Roo.bootstrap.SplitBar} this
34057 "beforeresize" : true,
34059 "beforeapply" : true
34062 Roo.util.Observable.call(this);
34065 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34066 onStartProxyDrag : function(x, y){
34067 this.fireEvent("beforeresize", this);
34069 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34071 o.enableDisplayMode("block");
34072 // all splitbars share the same overlay
34073 Roo.bootstrap.SplitBar.prototype.overlay = o;
34075 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34076 this.overlay.show();
34077 Roo.get(this.proxy).setDisplayed("block");
34078 var size = this.adapter.getElementSize(this);
34079 this.activeMinSize = this.getMinimumSize();;
34080 this.activeMaxSize = this.getMaximumSize();;
34081 var c1 = size - this.activeMinSize;
34082 var c2 = Math.max(this.activeMaxSize - size, 0);
34083 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34084 this.dd.resetConstraints();
34085 this.dd.setXConstraint(
34086 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34087 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34089 this.dd.setYConstraint(0, 0);
34091 this.dd.resetConstraints();
34092 this.dd.setXConstraint(0, 0);
34093 this.dd.setYConstraint(
34094 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34095 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34098 this.dragSpecs.startSize = size;
34099 this.dragSpecs.startPoint = [x, y];
34100 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34104 * @private Called after the drag operation by the DDProxy
34106 onEndProxyDrag : function(e){
34107 Roo.get(this.proxy).setDisplayed(false);
34108 var endPoint = Roo.lib.Event.getXY(e);
34110 this.overlay.hide();
34113 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34114 newSize = this.dragSpecs.startSize +
34115 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34116 endPoint[0] - this.dragSpecs.startPoint[0] :
34117 this.dragSpecs.startPoint[0] - endPoint[0]
34120 newSize = this.dragSpecs.startSize +
34121 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34122 endPoint[1] - this.dragSpecs.startPoint[1] :
34123 this.dragSpecs.startPoint[1] - endPoint[1]
34126 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34127 if(newSize != this.dragSpecs.startSize){
34128 if(this.fireEvent('beforeapply', this, newSize) !== false){
34129 this.adapter.setElementSize(this, newSize);
34130 this.fireEvent("moved", this, newSize);
34131 this.fireEvent("resize", this, newSize);
34137 * Get the adapter this SplitBar uses
34138 * @return The adapter object
34140 getAdapter : function(){
34141 return this.adapter;
34145 * Set the adapter this SplitBar uses
34146 * @param {Object} adapter A SplitBar adapter object
34148 setAdapter : function(adapter){
34149 this.adapter = adapter;
34150 this.adapter.init(this);
34154 * Gets the minimum size for the resizing element
34155 * @return {Number} The minimum size
34157 getMinimumSize : function(){
34158 return this.minSize;
34162 * Sets the minimum size for the resizing element
34163 * @param {Number} minSize The minimum size
34165 setMinimumSize : function(minSize){
34166 this.minSize = minSize;
34170 * Gets the maximum size for the resizing element
34171 * @return {Number} The maximum size
34173 getMaximumSize : function(){
34174 return this.maxSize;
34178 * Sets the maximum size for the resizing element
34179 * @param {Number} maxSize The maximum size
34181 setMaximumSize : function(maxSize){
34182 this.maxSize = maxSize;
34186 * Sets the initialize size for the resizing element
34187 * @param {Number} size The initial size
34189 setCurrentSize : function(size){
34190 var oldAnimate = this.animate;
34191 this.animate = false;
34192 this.adapter.setElementSize(this, size);
34193 this.animate = oldAnimate;
34197 * Destroy this splitbar.
34198 * @param {Boolean} removeEl True to remove the element
34200 destroy : function(removeEl){
34202 this.shim.remove();
34205 this.proxy.parentNode.removeChild(this.proxy);
34213 * @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.
34215 Roo.bootstrap.SplitBar.createProxy = function(dir){
34216 var proxy = new Roo.Element(document.createElement("div"));
34217 proxy.unselectable();
34218 var cls = 'roo-splitbar-proxy';
34219 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34220 document.body.appendChild(proxy.dom);
34225 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34226 * Default Adapter. It assumes the splitter and resizing element are not positioned
34227 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34229 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34232 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34233 // do nothing for now
34234 init : function(s){
34238 * Called before drag operations to get the current size of the resizing element.
34239 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34241 getElementSize : function(s){
34242 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34243 return s.resizingEl.getWidth();
34245 return s.resizingEl.getHeight();
34250 * Called after drag operations to set the size of the resizing element.
34251 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34252 * @param {Number} newSize The new size to set
34253 * @param {Function} onComplete A function to be invoked when resizing is complete
34255 setElementSize : function(s, newSize, onComplete){
34256 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34258 s.resizingEl.setWidth(newSize);
34260 onComplete(s, newSize);
34263 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34268 s.resizingEl.setHeight(newSize);
34270 onComplete(s, newSize);
34273 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34280 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34281 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34282 * Adapter that moves the splitter element to align with the resized sizing element.
34283 * Used with an absolute positioned SplitBar.
34284 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34285 * document.body, make sure you assign an id to the body element.
34287 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34288 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34289 this.container = Roo.get(container);
34292 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34293 init : function(s){
34294 this.basic.init(s);
34297 getElementSize : function(s){
34298 return this.basic.getElementSize(s);
34301 setElementSize : function(s, newSize, onComplete){
34302 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34305 moveSplitter : function(s){
34306 var yes = Roo.bootstrap.SplitBar;
34307 switch(s.placement){
34309 s.el.setX(s.resizingEl.getRight());
34312 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34315 s.el.setY(s.resizingEl.getBottom());
34318 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34325 * Orientation constant - Create a vertical SplitBar
34329 Roo.bootstrap.SplitBar.VERTICAL = 1;
34332 * Orientation constant - Create a horizontal SplitBar
34336 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34339 * Placement constant - The resizing element is to the left of the splitter element
34343 Roo.bootstrap.SplitBar.LEFT = 1;
34346 * Placement constant - The resizing element is to the right of the splitter element
34350 Roo.bootstrap.SplitBar.RIGHT = 2;
34353 * Placement constant - The resizing element is positioned above the splitter element
34357 Roo.bootstrap.SplitBar.TOP = 3;
34360 * Placement constant - The resizing element is positioned under splitter element
34364 Roo.bootstrap.SplitBar.BOTTOM = 4;
34365 Roo.namespace("Roo.bootstrap.layout");/*
34367 * Ext JS Library 1.1.1
34368 * Copyright(c) 2006-2007, Ext JS, LLC.
34370 * Originally Released Under LGPL - original licence link has changed is not relivant.
34373 * <script type="text/javascript">
34377 * @class Roo.bootstrap.layout.Manager
34378 * @extends Roo.bootstrap.Component
34379 * Base class for layout managers.
34381 Roo.bootstrap.layout.Manager = function(config)
34383 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34389 /** false to disable window resize monitoring @type Boolean */
34390 this.monitorWindowResize = true;
34395 * Fires when a layout is performed.
34396 * @param {Roo.LayoutManager} this
34400 * @event regionresized
34401 * Fires when the user resizes a region.
34402 * @param {Roo.LayoutRegion} region The resized region
34403 * @param {Number} newSize The new size (width for east/west, height for north/south)
34405 "regionresized" : true,
34407 * @event regioncollapsed
34408 * Fires when a region is collapsed.
34409 * @param {Roo.LayoutRegion} region The collapsed region
34411 "regioncollapsed" : true,
34413 * @event regionexpanded
34414 * Fires when a region is expanded.
34415 * @param {Roo.LayoutRegion} region The expanded region
34417 "regionexpanded" : true
34419 this.updating = false;
34422 this.el = Roo.get(config.el);
34428 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34433 monitorWindowResize : true,
34439 onRender : function(ct, position)
34442 this.el = Roo.get(ct);
34445 //this.fireEvent('render',this);
34449 initEvents: function()
34453 // ie scrollbar fix
34454 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34455 document.body.scroll = "no";
34456 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34457 this.el.position('relative');
34459 this.id = this.el.id;
34460 this.el.addClass("roo-layout-container");
34461 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34462 if(this.el.dom != document.body ) {
34463 this.el.on('resize', this.layout,this);
34464 this.el.on('show', this.layout,this);
34470 * Returns true if this layout is currently being updated
34471 * @return {Boolean}
34473 isUpdating : function(){
34474 return this.updating;
34478 * Suspend the LayoutManager from doing auto-layouts while
34479 * making multiple add or remove calls
34481 beginUpdate : function(){
34482 this.updating = true;
34486 * Restore auto-layouts and optionally disable the manager from performing a layout
34487 * @param {Boolean} noLayout true to disable a layout update
34489 endUpdate : function(noLayout){
34490 this.updating = false;
34496 layout: function(){
34500 onRegionResized : function(region, newSize){
34501 this.fireEvent("regionresized", region, newSize);
34505 onRegionCollapsed : function(region){
34506 this.fireEvent("regioncollapsed", region);
34509 onRegionExpanded : function(region){
34510 this.fireEvent("regionexpanded", region);
34514 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34515 * performs box-model adjustments.
34516 * @return {Object} The size as an object {width: (the width), height: (the height)}
34518 getViewSize : function()
34521 if(this.el.dom != document.body){
34522 size = this.el.getSize();
34524 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34526 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34527 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34532 * Returns the Element this layout is bound to.
34533 * @return {Roo.Element}
34535 getEl : function(){
34540 * Returns the specified region.
34541 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34542 * @return {Roo.LayoutRegion}
34544 getRegion : function(target){
34545 return this.regions[target.toLowerCase()];
34548 onWindowResize : function(){
34549 if(this.monitorWindowResize){
34556 * Ext JS Library 1.1.1
34557 * Copyright(c) 2006-2007, Ext JS, LLC.
34559 * Originally Released Under LGPL - original licence link has changed is not relivant.
34562 * <script type="text/javascript">
34565 * @class Roo.bootstrap.layout.Border
34566 * @extends Roo.bootstrap.layout.Manager
34567 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34568 * please see: examples/bootstrap/nested.html<br><br>
34570 <b>The container the layout is rendered into can be either the body element or any other element.
34571 If it is not the body element, the container needs to either be an absolute positioned element,
34572 or you will need to add "position:relative" to the css of the container. You will also need to specify
34573 the container size if it is not the body element.</b>
34576 * Create a new Border
34577 * @param {Object} config Configuration options
34579 Roo.bootstrap.layout.Border = function(config){
34580 config = config || {};
34581 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34585 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34586 if(config[region]){
34587 config[region].region = region;
34588 this.addRegion(config[region]);
34594 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34596 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34598 * Creates and adds a new region if it doesn't already exist.
34599 * @param {String} target The target region key (north, south, east, west or center).
34600 * @param {Object} config The regions config object
34601 * @return {BorderLayoutRegion} The new region
34603 addRegion : function(config)
34605 if(!this.regions[config.region]){
34606 var r = this.factory(config);
34607 this.bindRegion(r);
34609 return this.regions[config.region];
34613 bindRegion : function(r){
34614 this.regions[r.config.region] = r;
34616 r.on("visibilitychange", this.layout, this);
34617 r.on("paneladded", this.layout, this);
34618 r.on("panelremoved", this.layout, this);
34619 r.on("invalidated", this.layout, this);
34620 r.on("resized", this.onRegionResized, this);
34621 r.on("collapsed", this.onRegionCollapsed, this);
34622 r.on("expanded", this.onRegionExpanded, this);
34626 * Performs a layout update.
34628 layout : function()
34630 if(this.updating) {
34634 // render all the rebions if they have not been done alreayd?
34635 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34636 if(this.regions[region] && !this.regions[region].bodyEl){
34637 this.regions[region].onRender(this.el)
34641 var size = this.getViewSize();
34642 var w = size.width;
34643 var h = size.height;
34648 //var x = 0, y = 0;
34650 var rs = this.regions;
34651 var north = rs["north"];
34652 var south = rs["south"];
34653 var west = rs["west"];
34654 var east = rs["east"];
34655 var center = rs["center"];
34656 //if(this.hideOnLayout){ // not supported anymore
34657 //c.el.setStyle("display", "none");
34659 if(north && north.isVisible()){
34660 var b = north.getBox();
34661 var m = north.getMargins();
34662 b.width = w - (m.left+m.right);
34665 centerY = b.height + b.y + m.bottom;
34666 centerH -= centerY;
34667 north.updateBox(this.safeBox(b));
34669 if(south && south.isVisible()){
34670 var b = south.getBox();
34671 var m = south.getMargins();
34672 b.width = w - (m.left+m.right);
34674 var totalHeight = (b.height + m.top + m.bottom);
34675 b.y = h - totalHeight + m.top;
34676 centerH -= totalHeight;
34677 south.updateBox(this.safeBox(b));
34679 if(west && west.isVisible()){
34680 var b = west.getBox();
34681 var m = west.getMargins();
34682 b.height = centerH - (m.top+m.bottom);
34684 b.y = centerY + m.top;
34685 var totalWidth = (b.width + m.left + m.right);
34686 centerX += totalWidth;
34687 centerW -= totalWidth;
34688 west.updateBox(this.safeBox(b));
34690 if(east && east.isVisible()){
34691 var b = east.getBox();
34692 var m = east.getMargins();
34693 b.height = centerH - (m.top+m.bottom);
34694 var totalWidth = (b.width + m.left + m.right);
34695 b.x = w - totalWidth + m.left;
34696 b.y = centerY + m.top;
34697 centerW -= totalWidth;
34698 east.updateBox(this.safeBox(b));
34701 var m = center.getMargins();
34703 x: centerX + m.left,
34704 y: centerY + m.top,
34705 width: centerW - (m.left+m.right),
34706 height: centerH - (m.top+m.bottom)
34708 //if(this.hideOnLayout){
34709 //center.el.setStyle("display", "block");
34711 center.updateBox(this.safeBox(centerBox));
34714 this.fireEvent("layout", this);
34718 safeBox : function(box){
34719 box.width = Math.max(0, box.width);
34720 box.height = Math.max(0, box.height);
34725 * Adds a ContentPanel (or subclass) to this layout.
34726 * @param {String} target The target region key (north, south, east, west or center).
34727 * @param {Roo.ContentPanel} panel The panel to add
34728 * @return {Roo.ContentPanel} The added panel
34730 add : function(target, panel){
34732 target = target.toLowerCase();
34733 return this.regions[target].add(panel);
34737 * Remove a ContentPanel (or subclass) to this layout.
34738 * @param {String} target The target region key (north, south, east, west or center).
34739 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34740 * @return {Roo.ContentPanel} The removed panel
34742 remove : function(target, panel){
34743 target = target.toLowerCase();
34744 return this.regions[target].remove(panel);
34748 * Searches all regions for a panel with the specified id
34749 * @param {String} panelId
34750 * @return {Roo.ContentPanel} The panel or null if it wasn't found
34752 findPanel : function(panelId){
34753 var rs = this.regions;
34754 for(var target in rs){
34755 if(typeof rs[target] != "function"){
34756 var p = rs[target].getPanel(panelId);
34766 * Searches all regions for a panel with the specified id and activates (shows) it.
34767 * @param {String/ContentPanel} panelId The panels id or the panel itself
34768 * @return {Roo.ContentPanel} The shown panel or null
34770 showPanel : function(panelId) {
34771 var rs = this.regions;
34772 for(var target in rs){
34773 var r = rs[target];
34774 if(typeof r != "function"){
34775 if(r.hasPanel(panelId)){
34776 return r.showPanel(panelId);
34784 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34785 * @param {Roo.state.Provider} provider (optional) An alternate state provider
34788 restoreState : function(provider){
34790 provider = Roo.state.Manager;
34792 var sm = new Roo.LayoutStateManager();
34793 sm.init(this, provider);
34799 * Adds a xtype elements to the layout.
34803 xtype : 'ContentPanel',
34810 xtype : 'NestedLayoutPanel',
34816 items : [ ... list of content panels or nested layout panels.. ]
34820 * @param {Object} cfg Xtype definition of item to add.
34822 addxtype : function(cfg)
34824 // basically accepts a pannel...
34825 // can accept a layout region..!?!?
34826 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34829 // theory? children can only be panels??
34831 //if (!cfg.xtype.match(/Panel$/)) {
34836 if (typeof(cfg.region) == 'undefined') {
34837 Roo.log("Failed to add Panel, region was not set");
34841 var region = cfg.region;
34847 xitems = cfg.items;
34854 case 'Content': // ContentPanel (el, cfg)
34855 case 'Scroll': // ContentPanel (el, cfg)
34857 cfg.autoCreate = true;
34858 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34860 // var el = this.el.createChild();
34861 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34864 this.add(region, ret);
34868 case 'TreePanel': // our new panel!
34869 cfg.el = this.el.createChild();
34870 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34871 this.add(region, ret);
34876 // create a new Layout (which is a Border Layout...
34878 var clayout = cfg.layout;
34879 clayout.el = this.el.createChild();
34880 clayout.items = clayout.items || [];
34884 // replace this exitems with the clayout ones..
34885 xitems = clayout.items;
34887 // force background off if it's in center...
34888 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34889 cfg.background = false;
34891 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
34894 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34895 //console.log('adding nested layout panel ' + cfg.toSource());
34896 this.add(region, ret);
34897 nb = {}; /// find first...
34902 // needs grid and region
34904 //var el = this.getRegion(region).el.createChild();
34906 *var el = this.el.createChild();
34907 // create the grid first...
34908 cfg.grid.container = el;
34909 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34912 if (region == 'center' && this.active ) {
34913 cfg.background = false;
34916 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34918 this.add(region, ret);
34920 if (cfg.background) {
34921 // render grid on panel activation (if panel background)
34922 ret.on('activate', function(gp) {
34923 if (!gp.grid.rendered) {
34924 // gp.grid.render(el);
34928 // cfg.grid.render(el);
34934 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34935 // it was the old xcomponent building that caused this before.
34936 // espeically if border is the top element in the tree.
34946 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34948 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34949 this.add(region, ret);
34953 throw "Can not add '" + cfg.xtype + "' to Border";
34959 this.beginUpdate();
34963 Roo.each(xitems, function(i) {
34964 region = nb && i.region ? i.region : false;
34966 var add = ret.addxtype(i);
34969 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
34970 if (!i.background) {
34971 abn[region] = nb[region] ;
34978 // make the last non-background panel active..
34979 //if (nb) { Roo.log(abn); }
34982 for(var r in abn) {
34983 region = this.getRegion(r);
34985 // tried using nb[r], but it does not work..
34987 region.showPanel(abn[r]);
34998 factory : function(cfg)
35001 var validRegions = Roo.bootstrap.layout.Border.regions;
35003 var target = cfg.region;
35006 var r = Roo.bootstrap.layout;
35010 return new r.North(cfg);
35012 return new r.South(cfg);
35014 return new r.East(cfg);
35016 return new r.West(cfg);
35018 return new r.Center(cfg);
35020 throw 'Layout region "'+target+'" not supported.';
35027 * Ext JS Library 1.1.1
35028 * Copyright(c) 2006-2007, Ext JS, LLC.
35030 * Originally Released Under LGPL - original licence link has changed is not relivant.
35033 * <script type="text/javascript">
35037 * @class Roo.bootstrap.layout.Basic
35038 * @extends Roo.util.Observable
35039 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35040 * and does not have a titlebar, tabs or any other features. All it does is size and position
35041 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35042 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35043 * @cfg {string} region the region that it inhabits..
35044 * @cfg {bool} skipConfig skip config?
35048 Roo.bootstrap.layout.Basic = function(config){
35050 this.mgr = config.mgr;
35052 this.position = config.region;
35054 var skipConfig = config.skipConfig;
35058 * @scope Roo.BasicLayoutRegion
35062 * @event beforeremove
35063 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35064 * @param {Roo.LayoutRegion} this
35065 * @param {Roo.ContentPanel} panel The panel
35066 * @param {Object} e The cancel event object
35068 "beforeremove" : true,
35070 * @event invalidated
35071 * Fires when the layout for this region is changed.
35072 * @param {Roo.LayoutRegion} this
35074 "invalidated" : true,
35076 * @event visibilitychange
35077 * Fires when this region is shown or hidden
35078 * @param {Roo.LayoutRegion} this
35079 * @param {Boolean} visibility true or false
35081 "visibilitychange" : true,
35083 * @event paneladded
35084 * Fires when a panel is added.
35085 * @param {Roo.LayoutRegion} this
35086 * @param {Roo.ContentPanel} panel The panel
35088 "paneladded" : true,
35090 * @event panelremoved
35091 * Fires when a panel is removed.
35092 * @param {Roo.LayoutRegion} this
35093 * @param {Roo.ContentPanel} panel The panel
35095 "panelremoved" : true,
35097 * @event beforecollapse
35098 * Fires when this region before collapse.
35099 * @param {Roo.LayoutRegion} this
35101 "beforecollapse" : true,
35104 * Fires when this region is collapsed.
35105 * @param {Roo.LayoutRegion} this
35107 "collapsed" : true,
35110 * Fires when this region is expanded.
35111 * @param {Roo.LayoutRegion} this
35116 * Fires when this region is slid into view.
35117 * @param {Roo.LayoutRegion} this
35119 "slideshow" : true,
35122 * Fires when this region slides out of view.
35123 * @param {Roo.LayoutRegion} this
35125 "slidehide" : true,
35127 * @event panelactivated
35128 * Fires when a panel is activated.
35129 * @param {Roo.LayoutRegion} this
35130 * @param {Roo.ContentPanel} panel The activated panel
35132 "panelactivated" : true,
35135 * Fires when the user resizes this region.
35136 * @param {Roo.LayoutRegion} this
35137 * @param {Number} newSize The new size (width for east/west, height for north/south)
35141 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35142 this.panels = new Roo.util.MixedCollection();
35143 this.panels.getKey = this.getPanelId.createDelegate(this);
35145 this.activePanel = null;
35146 // ensure listeners are added...
35148 if (config.listeners || config.events) {
35149 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35150 listeners : config.listeners || {},
35151 events : config.events || {}
35155 if(skipConfig !== true){
35156 this.applyConfig(config);
35160 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35162 getPanelId : function(p){
35166 applyConfig : function(config){
35167 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35168 this.config = config;
35173 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35174 * the width, for horizontal (north, south) the height.
35175 * @param {Number} newSize The new width or height
35177 resizeTo : function(newSize){
35178 var el = this.el ? this.el :
35179 (this.activePanel ? this.activePanel.getEl() : null);
35181 switch(this.position){
35184 el.setWidth(newSize);
35185 this.fireEvent("resized", this, newSize);
35189 el.setHeight(newSize);
35190 this.fireEvent("resized", this, newSize);
35196 getBox : function(){
35197 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35200 getMargins : function(){
35201 return this.margins;
35204 updateBox : function(box){
35206 var el = this.activePanel.getEl();
35207 el.dom.style.left = box.x + "px";
35208 el.dom.style.top = box.y + "px";
35209 this.activePanel.setSize(box.width, box.height);
35213 * Returns the container element for this region.
35214 * @return {Roo.Element}
35216 getEl : function(){
35217 return this.activePanel;
35221 * Returns true if this region is currently visible.
35222 * @return {Boolean}
35224 isVisible : function(){
35225 return this.activePanel ? true : false;
35228 setActivePanel : function(panel){
35229 panel = this.getPanel(panel);
35230 if(this.activePanel && this.activePanel != panel){
35231 this.activePanel.setActiveState(false);
35232 this.activePanel.getEl().setLeftTop(-10000,-10000);
35234 this.activePanel = panel;
35235 panel.setActiveState(true);
35237 panel.setSize(this.box.width, this.box.height);
35239 this.fireEvent("panelactivated", this, panel);
35240 this.fireEvent("invalidated");
35244 * Show the specified panel.
35245 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35246 * @return {Roo.ContentPanel} The shown panel or null
35248 showPanel : function(panel){
35249 panel = this.getPanel(panel);
35251 this.setActivePanel(panel);
35257 * Get the active panel for this region.
35258 * @return {Roo.ContentPanel} The active panel or null
35260 getActivePanel : function(){
35261 return this.activePanel;
35265 * Add the passed ContentPanel(s)
35266 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35267 * @return {Roo.ContentPanel} The panel added (if only one was added)
35269 add : function(panel){
35270 if(arguments.length > 1){
35271 for(var i = 0, len = arguments.length; i < len; i++) {
35272 this.add(arguments[i]);
35276 if(this.hasPanel(panel)){
35277 this.showPanel(panel);
35280 var el = panel.getEl();
35281 if(el.dom.parentNode != this.mgr.el.dom){
35282 this.mgr.el.dom.appendChild(el.dom);
35284 if(panel.setRegion){
35285 panel.setRegion(this);
35287 this.panels.add(panel);
35288 el.setStyle("position", "absolute");
35289 if(!panel.background){
35290 this.setActivePanel(panel);
35291 if(this.config.initialSize && this.panels.getCount()==1){
35292 this.resizeTo(this.config.initialSize);
35295 this.fireEvent("paneladded", this, panel);
35300 * Returns true if the panel is in this region.
35301 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35302 * @return {Boolean}
35304 hasPanel : function(panel){
35305 if(typeof panel == "object"){ // must be panel obj
35306 panel = panel.getId();
35308 return this.getPanel(panel) ? true : false;
35312 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35313 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35314 * @param {Boolean} preservePanel Overrides the config preservePanel option
35315 * @return {Roo.ContentPanel} The panel that was removed
35317 remove : function(panel, preservePanel){
35318 panel = this.getPanel(panel);
35323 this.fireEvent("beforeremove", this, panel, e);
35324 if(e.cancel === true){
35327 var panelId = panel.getId();
35328 this.panels.removeKey(panelId);
35333 * Returns the panel specified or null if it's not in this region.
35334 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35335 * @return {Roo.ContentPanel}
35337 getPanel : function(id){
35338 if(typeof id == "object"){ // must be panel obj
35341 return this.panels.get(id);
35345 * Returns this regions position (north/south/east/west/center).
35348 getPosition: function(){
35349 return this.position;
35353 * Ext JS Library 1.1.1
35354 * Copyright(c) 2006-2007, Ext JS, LLC.
35356 * Originally Released Under LGPL - original licence link has changed is not relivant.
35359 * <script type="text/javascript">
35363 * @class Roo.bootstrap.layout.Region
35364 * @extends Roo.bootstrap.layout.Basic
35365 * This class represents a region in a layout manager.
35367 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35368 * @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})
35369 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35370 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35371 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35372 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35373 * @cfg {String} title The title for the region (overrides panel titles)
35374 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35375 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35376 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35377 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35378 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35379 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35380 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35381 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35382 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35383 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35385 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35386 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35387 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35388 * @cfg {Number} width For East/West panels
35389 * @cfg {Number} height For North/South panels
35390 * @cfg {Boolean} split To show the splitter
35391 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35393 * @cfg {string} cls Extra CSS classes to add to region
35395 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35396 * @cfg {string} region the region that it inhabits..
35399 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35400 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35402 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35403 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35404 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35406 Roo.bootstrap.layout.Region = function(config)
35408 this.applyConfig(config);
35410 var mgr = config.mgr;
35411 var pos = config.region;
35412 config.skipConfig = true;
35413 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35416 this.onRender(mgr.el);
35419 this.visible = true;
35420 this.collapsed = false;
35421 this.unrendered_panels = [];
35424 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35426 position: '', // set by wrapper (eg. north/south etc..)
35427 unrendered_panels : null, // unrendered panels.
35428 createBody : function(){
35429 /** This region's body element
35430 * @type Roo.Element */
35431 this.bodyEl = this.el.createChild({
35433 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35437 onRender: function(ctr, pos)
35439 var dh = Roo.DomHelper;
35440 /** This region's container element
35441 * @type Roo.Element */
35442 this.el = dh.append(ctr.dom, {
35444 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35446 /** This region's title element
35447 * @type Roo.Element */
35449 this.titleEl = dh.append(this.el.dom,
35452 unselectable: "on",
35453 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35455 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35456 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35459 this.titleEl.enableDisplayMode();
35460 /** This region's title text element
35461 * @type HTMLElement */
35462 this.titleTextEl = this.titleEl.dom.firstChild;
35463 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35465 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35466 this.closeBtn.enableDisplayMode();
35467 this.closeBtn.on("click", this.closeClicked, this);
35468 this.closeBtn.hide();
35470 this.createBody(this.config);
35471 if(this.config.hideWhenEmpty){
35473 this.on("paneladded", this.validateVisibility, this);
35474 this.on("panelremoved", this.validateVisibility, this);
35476 if(this.autoScroll){
35477 this.bodyEl.setStyle("overflow", "auto");
35479 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35481 //if(c.titlebar !== false){
35482 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35483 this.titleEl.hide();
35485 this.titleEl.show();
35486 if(this.config.title){
35487 this.titleTextEl.innerHTML = this.config.title;
35491 if(this.config.collapsed){
35492 this.collapse(true);
35494 if(this.config.hidden){
35498 if (this.unrendered_panels && this.unrendered_panels.length) {
35499 for (var i =0;i< this.unrendered_panels.length; i++) {
35500 this.add(this.unrendered_panels[i]);
35502 this.unrendered_panels = null;
35508 applyConfig : function(c)
35511 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35512 var dh = Roo.DomHelper;
35513 if(c.titlebar !== false){
35514 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35515 this.collapseBtn.on("click", this.collapse, this);
35516 this.collapseBtn.enableDisplayMode();
35518 if(c.showPin === true || this.showPin){
35519 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35520 this.stickBtn.enableDisplayMode();
35521 this.stickBtn.on("click", this.expand, this);
35522 this.stickBtn.hide();
35527 /** This region's collapsed element
35528 * @type Roo.Element */
35531 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35532 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35535 if(c.floatable !== false){
35536 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35537 this.collapsedEl.on("click", this.collapseClick, this);
35540 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35541 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35542 id: "message", unselectable: "on", style:{"float":"left"}});
35543 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35545 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35546 this.expandBtn.on("click", this.expand, this);
35550 if(this.collapseBtn){
35551 this.collapseBtn.setVisible(c.collapsible == true);
35554 this.cmargins = c.cmargins || this.cmargins ||
35555 (this.position == "west" || this.position == "east" ?
35556 {top: 0, left: 2, right:2, bottom: 0} :
35557 {top: 2, left: 0, right:0, bottom: 2});
35559 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35562 this.bottomTabs = c.tabPosition != "top";
35564 this.autoScroll = c.autoScroll || false;
35569 this.duration = c.duration || .30;
35570 this.slideDuration = c.slideDuration || .45;
35575 * Returns true if this region is currently visible.
35576 * @return {Boolean}
35578 isVisible : function(){
35579 return this.visible;
35583 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35584 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35586 //setCollapsedTitle : function(title){
35587 // title = title || " ";
35588 // if(this.collapsedTitleTextEl){
35589 // this.collapsedTitleTextEl.innerHTML = title;
35593 getBox : function(){
35595 // if(!this.collapsed){
35596 b = this.el.getBox(false, true);
35598 // b = this.collapsedEl.getBox(false, true);
35603 getMargins : function(){
35604 return this.margins;
35605 //return this.collapsed ? this.cmargins : this.margins;
35608 highlight : function(){
35609 this.el.addClass("x-layout-panel-dragover");
35612 unhighlight : function(){
35613 this.el.removeClass("x-layout-panel-dragover");
35616 updateBox : function(box)
35618 if (!this.bodyEl) {
35619 return; // not rendered yet..
35623 if(!this.collapsed){
35624 this.el.dom.style.left = box.x + "px";
35625 this.el.dom.style.top = box.y + "px";
35626 this.updateBody(box.width, box.height);
35628 this.collapsedEl.dom.style.left = box.x + "px";
35629 this.collapsedEl.dom.style.top = box.y + "px";
35630 this.collapsedEl.setSize(box.width, box.height);
35633 this.tabs.autoSizeTabs();
35637 updateBody : function(w, h)
35640 this.el.setWidth(w);
35641 w -= this.el.getBorderWidth("rl");
35642 if(this.config.adjustments){
35643 w += this.config.adjustments[0];
35646 if(h !== null && h > 0){
35647 this.el.setHeight(h);
35648 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35649 h -= this.el.getBorderWidth("tb");
35650 if(this.config.adjustments){
35651 h += this.config.adjustments[1];
35653 this.bodyEl.setHeight(h);
35655 h = this.tabs.syncHeight(h);
35658 if(this.panelSize){
35659 w = w !== null ? w : this.panelSize.width;
35660 h = h !== null ? h : this.panelSize.height;
35662 if(this.activePanel){
35663 var el = this.activePanel.getEl();
35664 w = w !== null ? w : el.getWidth();
35665 h = h !== null ? h : el.getHeight();
35666 this.panelSize = {width: w, height: h};
35667 this.activePanel.setSize(w, h);
35669 if(Roo.isIE && this.tabs){
35670 this.tabs.el.repaint();
35675 * Returns the container element for this region.
35676 * @return {Roo.Element}
35678 getEl : function(){
35683 * Hides this region.
35686 //if(!this.collapsed){
35687 this.el.dom.style.left = "-2000px";
35690 // this.collapsedEl.dom.style.left = "-2000px";
35691 // this.collapsedEl.hide();
35693 this.visible = false;
35694 this.fireEvent("visibilitychange", this, false);
35698 * Shows this region if it was previously hidden.
35701 //if(!this.collapsed){
35704 // this.collapsedEl.show();
35706 this.visible = true;
35707 this.fireEvent("visibilitychange", this, true);
35710 closeClicked : function(){
35711 if(this.activePanel){
35712 this.remove(this.activePanel);
35716 collapseClick : function(e){
35718 e.stopPropagation();
35721 e.stopPropagation();
35727 * Collapses this region.
35728 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35731 collapse : function(skipAnim, skipCheck = false){
35732 if(this.collapsed) {
35736 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35738 this.collapsed = true;
35740 this.split.el.hide();
35742 if(this.config.animate && skipAnim !== true){
35743 this.fireEvent("invalidated", this);
35744 this.animateCollapse();
35746 this.el.setLocation(-20000,-20000);
35748 this.collapsedEl.show();
35749 this.fireEvent("collapsed", this);
35750 this.fireEvent("invalidated", this);
35756 animateCollapse : function(){
35761 * Expands this region if it was previously collapsed.
35762 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35763 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35766 expand : function(e, skipAnim){
35768 e.stopPropagation();
35770 if(!this.collapsed || this.el.hasActiveFx()) {
35774 this.afterSlideIn();
35777 this.collapsed = false;
35778 if(this.config.animate && skipAnim !== true){
35779 this.animateExpand();
35783 this.split.el.show();
35785 this.collapsedEl.setLocation(-2000,-2000);
35786 this.collapsedEl.hide();
35787 this.fireEvent("invalidated", this);
35788 this.fireEvent("expanded", this);
35792 animateExpand : function(){
35796 initTabs : function()
35798 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35800 var ts = new Roo.bootstrap.panel.Tabs({
35801 el: this.bodyEl.dom,
35802 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35803 disableTooltips: this.config.disableTabTips,
35804 toolbar : this.config.toolbar
35807 if(this.config.hideTabs){
35808 ts.stripWrap.setDisplayed(false);
35811 ts.resizeTabs = this.config.resizeTabs === true;
35812 ts.minTabWidth = this.config.minTabWidth || 40;
35813 ts.maxTabWidth = this.config.maxTabWidth || 250;
35814 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35815 ts.monitorResize = false;
35816 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35817 ts.bodyEl.addClass('roo-layout-tabs-body');
35818 this.panels.each(this.initPanelAsTab, this);
35821 initPanelAsTab : function(panel){
35822 var ti = this.tabs.addTab(
35826 this.config.closeOnTab && panel.isClosable(),
35829 if(panel.tabTip !== undefined){
35830 ti.setTooltip(panel.tabTip);
35832 ti.on("activate", function(){
35833 this.setActivePanel(panel);
35836 if(this.config.closeOnTab){
35837 ti.on("beforeclose", function(t, e){
35839 this.remove(panel);
35843 panel.tabItem = ti;
35848 updatePanelTitle : function(panel, title)
35850 if(this.activePanel == panel){
35851 this.updateTitle(title);
35854 var ti = this.tabs.getTab(panel.getEl().id);
35856 if(panel.tabTip !== undefined){
35857 ti.setTooltip(panel.tabTip);
35862 updateTitle : function(title){
35863 if(this.titleTextEl && !this.config.title){
35864 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
35868 setActivePanel : function(panel)
35870 panel = this.getPanel(panel);
35871 if(this.activePanel && this.activePanel != panel){
35872 if(this.activePanel.setActiveState(false) === false){
35876 this.activePanel = panel;
35877 panel.setActiveState(true);
35878 if(this.panelSize){
35879 panel.setSize(this.panelSize.width, this.panelSize.height);
35882 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35884 this.updateTitle(panel.getTitle());
35886 this.fireEvent("invalidated", this);
35888 this.fireEvent("panelactivated", this, panel);
35892 * Shows the specified panel.
35893 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35894 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35896 showPanel : function(panel)
35898 panel = this.getPanel(panel);
35901 var tab = this.tabs.getTab(panel.getEl().id);
35902 if(tab.isHidden()){
35903 this.tabs.unhideTab(tab.id);
35907 this.setActivePanel(panel);
35914 * Get the active panel for this region.
35915 * @return {Roo.ContentPanel} The active panel or null
35917 getActivePanel : function(){
35918 return this.activePanel;
35921 validateVisibility : function(){
35922 if(this.panels.getCount() < 1){
35923 this.updateTitle(" ");
35924 this.closeBtn.hide();
35927 if(!this.isVisible()){
35934 * Adds the passed ContentPanel(s) to this region.
35935 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35936 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35938 add : function(panel)
35940 if(arguments.length > 1){
35941 for(var i = 0, len = arguments.length; i < len; i++) {
35942 this.add(arguments[i]);
35947 // if we have not been rendered yet, then we can not really do much of this..
35948 if (!this.bodyEl) {
35949 this.unrendered_panels.push(panel);
35956 if(this.hasPanel(panel)){
35957 this.showPanel(panel);
35960 panel.setRegion(this);
35961 this.panels.add(panel);
35962 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
35963 // sinle panel - no tab...?? would it not be better to render it with the tabs,
35964 // and hide them... ???
35965 this.bodyEl.dom.appendChild(panel.getEl().dom);
35966 if(panel.background !== true){
35967 this.setActivePanel(panel);
35969 this.fireEvent("paneladded", this, panel);
35976 this.initPanelAsTab(panel);
35980 if(panel.background !== true){
35981 this.tabs.activate(panel.getEl().id);
35983 this.fireEvent("paneladded", this, panel);
35988 * Hides the tab for the specified panel.
35989 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
35991 hidePanel : function(panel){
35992 if(this.tabs && (panel = this.getPanel(panel))){
35993 this.tabs.hideTab(panel.getEl().id);
35998 * Unhides the tab for a previously hidden panel.
35999 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36001 unhidePanel : function(panel){
36002 if(this.tabs && (panel = this.getPanel(panel))){
36003 this.tabs.unhideTab(panel.getEl().id);
36007 clearPanels : function(){
36008 while(this.panels.getCount() > 0){
36009 this.remove(this.panels.first());
36014 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36015 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36016 * @param {Boolean} preservePanel Overrides the config preservePanel option
36017 * @return {Roo.ContentPanel} The panel that was removed
36019 remove : function(panel, preservePanel)
36021 panel = this.getPanel(panel);
36026 this.fireEvent("beforeremove", this, panel, e);
36027 if(e.cancel === true){
36030 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36031 var panelId = panel.getId();
36032 this.panels.removeKey(panelId);
36034 document.body.appendChild(panel.getEl().dom);
36037 this.tabs.removeTab(panel.getEl().id);
36038 }else if (!preservePanel){
36039 this.bodyEl.dom.removeChild(panel.getEl().dom);
36041 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36042 var p = this.panels.first();
36043 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36044 tempEl.appendChild(p.getEl().dom);
36045 this.bodyEl.update("");
36046 this.bodyEl.dom.appendChild(p.getEl().dom);
36048 this.updateTitle(p.getTitle());
36050 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36051 this.setActivePanel(p);
36053 panel.setRegion(null);
36054 if(this.activePanel == panel){
36055 this.activePanel = null;
36057 if(this.config.autoDestroy !== false && preservePanel !== true){
36058 try{panel.destroy();}catch(e){}
36060 this.fireEvent("panelremoved", this, panel);
36065 * Returns the TabPanel component used by this region
36066 * @return {Roo.TabPanel}
36068 getTabs : function(){
36072 createTool : function(parentEl, className){
36073 var btn = Roo.DomHelper.append(parentEl, {
36075 cls: "x-layout-tools-button",
36078 cls: "roo-layout-tools-button-inner " + className,
36082 btn.addClassOnOver("roo-layout-tools-button-over");
36087 * Ext JS Library 1.1.1
36088 * Copyright(c) 2006-2007, Ext JS, LLC.
36090 * Originally Released Under LGPL - original licence link has changed is not relivant.
36093 * <script type="text/javascript">
36099 * @class Roo.SplitLayoutRegion
36100 * @extends Roo.LayoutRegion
36101 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36103 Roo.bootstrap.layout.Split = function(config){
36104 this.cursor = config.cursor;
36105 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36108 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36110 splitTip : "Drag to resize.",
36111 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36112 useSplitTips : false,
36114 applyConfig : function(config){
36115 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36118 onRender : function(ctr,pos) {
36120 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36121 if(!this.config.split){
36126 var splitEl = Roo.DomHelper.append(ctr.dom, {
36128 id: this.el.id + "-split",
36129 cls: "roo-layout-split roo-layout-split-"+this.position,
36132 /** The SplitBar for this region
36133 * @type Roo.SplitBar */
36134 // does not exist yet...
36135 Roo.log([this.position, this.orientation]);
36137 this.split = new Roo.bootstrap.SplitBar({
36138 dragElement : splitEl,
36139 resizingElement: this.el,
36140 orientation : this.orientation
36143 this.split.on("moved", this.onSplitMove, this);
36144 this.split.useShim = this.config.useShim === true;
36145 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36146 if(this.useSplitTips){
36147 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36149 //if(config.collapsible){
36150 // this.split.el.on("dblclick", this.collapse, this);
36153 if(typeof this.config.minSize != "undefined"){
36154 this.split.minSize = this.config.minSize;
36156 if(typeof this.config.maxSize != "undefined"){
36157 this.split.maxSize = this.config.maxSize;
36159 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36160 this.hideSplitter();
36165 getHMaxSize : function(){
36166 var cmax = this.config.maxSize || 10000;
36167 var center = this.mgr.getRegion("center");
36168 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36171 getVMaxSize : function(){
36172 var cmax = this.config.maxSize || 10000;
36173 var center = this.mgr.getRegion("center");
36174 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36177 onSplitMove : function(split, newSize){
36178 this.fireEvent("resized", this, newSize);
36182 * Returns the {@link Roo.SplitBar} for this region.
36183 * @return {Roo.SplitBar}
36185 getSplitBar : function(){
36190 this.hideSplitter();
36191 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36194 hideSplitter : function(){
36196 this.split.el.setLocation(-2000,-2000);
36197 this.split.el.hide();
36203 this.split.el.show();
36205 Roo.bootstrap.layout.Split.superclass.show.call(this);
36208 beforeSlide: function(){
36209 if(Roo.isGecko){// firefox overflow auto bug workaround
36210 this.bodyEl.clip();
36212 this.tabs.bodyEl.clip();
36214 if(this.activePanel){
36215 this.activePanel.getEl().clip();
36217 if(this.activePanel.beforeSlide){
36218 this.activePanel.beforeSlide();
36224 afterSlide : function(){
36225 if(Roo.isGecko){// firefox overflow auto bug workaround
36226 this.bodyEl.unclip();
36228 this.tabs.bodyEl.unclip();
36230 if(this.activePanel){
36231 this.activePanel.getEl().unclip();
36232 if(this.activePanel.afterSlide){
36233 this.activePanel.afterSlide();
36239 initAutoHide : function(){
36240 if(this.autoHide !== false){
36241 if(!this.autoHideHd){
36242 var st = new Roo.util.DelayedTask(this.slideIn, this);
36243 this.autoHideHd = {
36244 "mouseout": function(e){
36245 if(!e.within(this.el, true)){
36249 "mouseover" : function(e){
36255 this.el.on(this.autoHideHd);
36259 clearAutoHide : function(){
36260 if(this.autoHide !== false){
36261 this.el.un("mouseout", this.autoHideHd.mouseout);
36262 this.el.un("mouseover", this.autoHideHd.mouseover);
36266 clearMonitor : function(){
36267 Roo.get(document).un("click", this.slideInIf, this);
36270 // these names are backwards but not changed for compat
36271 slideOut : function(){
36272 if(this.isSlid || this.el.hasActiveFx()){
36275 this.isSlid = true;
36276 if(this.collapseBtn){
36277 this.collapseBtn.hide();
36279 this.closeBtnState = this.closeBtn.getStyle('display');
36280 this.closeBtn.hide();
36282 this.stickBtn.show();
36285 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36286 this.beforeSlide();
36287 this.el.setStyle("z-index", 10001);
36288 this.el.slideIn(this.getSlideAnchor(), {
36289 callback: function(){
36291 this.initAutoHide();
36292 Roo.get(document).on("click", this.slideInIf, this);
36293 this.fireEvent("slideshow", this);
36300 afterSlideIn : function(){
36301 this.clearAutoHide();
36302 this.isSlid = false;
36303 this.clearMonitor();
36304 this.el.setStyle("z-index", "");
36305 if(this.collapseBtn){
36306 this.collapseBtn.show();
36308 this.closeBtn.setStyle('display', this.closeBtnState);
36310 this.stickBtn.hide();
36312 this.fireEvent("slidehide", this);
36315 slideIn : function(cb){
36316 if(!this.isSlid || this.el.hasActiveFx()){
36320 this.isSlid = false;
36321 this.beforeSlide();
36322 this.el.slideOut(this.getSlideAnchor(), {
36323 callback: function(){
36324 this.el.setLeftTop(-10000, -10000);
36326 this.afterSlideIn();
36334 slideInIf : function(e){
36335 if(!e.within(this.el)){
36340 animateCollapse : function(){
36341 this.beforeSlide();
36342 this.el.setStyle("z-index", 20000);
36343 var anchor = this.getSlideAnchor();
36344 this.el.slideOut(anchor, {
36345 callback : function(){
36346 this.el.setStyle("z-index", "");
36347 this.collapsedEl.slideIn(anchor, {duration:.3});
36349 this.el.setLocation(-10000,-10000);
36351 this.fireEvent("collapsed", this);
36358 animateExpand : function(){
36359 this.beforeSlide();
36360 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36361 this.el.setStyle("z-index", 20000);
36362 this.collapsedEl.hide({
36365 this.el.slideIn(this.getSlideAnchor(), {
36366 callback : function(){
36367 this.el.setStyle("z-index", "");
36370 this.split.el.show();
36372 this.fireEvent("invalidated", this);
36373 this.fireEvent("expanded", this);
36401 getAnchor : function(){
36402 return this.anchors[this.position];
36405 getCollapseAnchor : function(){
36406 return this.canchors[this.position];
36409 getSlideAnchor : function(){
36410 return this.sanchors[this.position];
36413 getAlignAdj : function(){
36414 var cm = this.cmargins;
36415 switch(this.position){
36431 getExpandAdj : function(){
36432 var c = this.collapsedEl, cm = this.cmargins;
36433 switch(this.position){
36435 return [-(cm.right+c.getWidth()+cm.left), 0];
36438 return [cm.right+c.getWidth()+cm.left, 0];
36441 return [0, -(cm.top+cm.bottom+c.getHeight())];
36444 return [0, cm.top+cm.bottom+c.getHeight()];
36450 * Ext JS Library 1.1.1
36451 * Copyright(c) 2006-2007, Ext JS, LLC.
36453 * Originally Released Under LGPL - original licence link has changed is not relivant.
36456 * <script type="text/javascript">
36459 * These classes are private internal classes
36461 Roo.bootstrap.layout.Center = function(config){
36462 config.region = "center";
36463 Roo.bootstrap.layout.Region.call(this, config);
36464 this.visible = true;
36465 this.minWidth = config.minWidth || 20;
36466 this.minHeight = config.minHeight || 20;
36469 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36471 // center panel can't be hidden
36475 // center panel can't be hidden
36478 getMinWidth: function(){
36479 return this.minWidth;
36482 getMinHeight: function(){
36483 return this.minHeight;
36496 Roo.bootstrap.layout.North = function(config)
36498 config.region = 'north';
36499 config.cursor = 'n-resize';
36501 Roo.bootstrap.layout.Split.call(this, config);
36505 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36506 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36507 this.split.el.addClass("roo-layout-split-v");
36509 var size = config.initialSize || config.height;
36510 if(typeof size != "undefined"){
36511 this.el.setHeight(size);
36514 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36516 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36520 getBox : function(){
36521 if(this.collapsed){
36522 return this.collapsedEl.getBox();
36524 var box = this.el.getBox();
36526 box.height += this.split.el.getHeight();
36531 updateBox : function(box){
36532 if(this.split && !this.collapsed){
36533 box.height -= this.split.el.getHeight();
36534 this.split.el.setLeft(box.x);
36535 this.split.el.setTop(box.y+box.height);
36536 this.split.el.setWidth(box.width);
36538 if(this.collapsed){
36539 this.updateBody(box.width, null);
36541 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36549 Roo.bootstrap.layout.South = function(config){
36550 config.region = 'south';
36551 config.cursor = 's-resize';
36552 Roo.bootstrap.layout.Split.call(this, config);
36554 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36555 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36556 this.split.el.addClass("roo-layout-split-v");
36558 var size = config.initialSize || config.height;
36559 if(typeof size != "undefined"){
36560 this.el.setHeight(size);
36564 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36565 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36566 getBox : function(){
36567 if(this.collapsed){
36568 return this.collapsedEl.getBox();
36570 var box = this.el.getBox();
36572 var sh = this.split.el.getHeight();
36579 updateBox : function(box){
36580 if(this.split && !this.collapsed){
36581 var sh = this.split.el.getHeight();
36584 this.split.el.setLeft(box.x);
36585 this.split.el.setTop(box.y-sh);
36586 this.split.el.setWidth(box.width);
36588 if(this.collapsed){
36589 this.updateBody(box.width, null);
36591 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36595 Roo.bootstrap.layout.East = function(config){
36596 config.region = "east";
36597 config.cursor = "e-resize";
36598 Roo.bootstrap.layout.Split.call(this, config);
36600 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36601 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36602 this.split.el.addClass("roo-layout-split-h");
36604 var size = config.initialSize || config.width;
36605 if(typeof size != "undefined"){
36606 this.el.setWidth(size);
36609 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36610 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36611 getBox : function(){
36612 if(this.collapsed){
36613 return this.collapsedEl.getBox();
36615 var box = this.el.getBox();
36617 var sw = this.split.el.getWidth();
36624 updateBox : function(box){
36625 if(this.split && !this.collapsed){
36626 var sw = this.split.el.getWidth();
36628 this.split.el.setLeft(box.x);
36629 this.split.el.setTop(box.y);
36630 this.split.el.setHeight(box.height);
36633 if(this.collapsed){
36634 this.updateBody(null, box.height);
36636 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36640 Roo.bootstrap.layout.West = function(config){
36641 config.region = "west";
36642 config.cursor = "w-resize";
36644 Roo.bootstrap.layout.Split.call(this, config);
36646 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36647 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36648 this.split.el.addClass("roo-layout-split-h");
36652 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36653 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36655 onRender: function(ctr, pos)
36657 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36658 var size = this.config.initialSize || this.config.width;
36659 if(typeof size != "undefined"){
36660 this.el.setWidth(size);
36664 getBox : function(){
36665 if(this.collapsed){
36666 return this.collapsedEl.getBox();
36668 var box = this.el.getBox();
36670 box.width += this.split.el.getWidth();
36675 updateBox : function(box){
36676 if(this.split && !this.collapsed){
36677 var sw = this.split.el.getWidth();
36679 this.split.el.setLeft(box.x+box.width);
36680 this.split.el.setTop(box.y);
36681 this.split.el.setHeight(box.height);
36683 if(this.collapsed){
36684 this.updateBody(null, box.height);
36686 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36689 Roo.namespace("Roo.bootstrap.panel");/*
36691 * Ext JS Library 1.1.1
36692 * Copyright(c) 2006-2007, Ext JS, LLC.
36694 * Originally Released Under LGPL - original licence link has changed is not relivant.
36697 * <script type="text/javascript">
36700 * @class Roo.ContentPanel
36701 * @extends Roo.util.Observable
36702 * A basic ContentPanel element.
36703 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36704 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36705 * @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
36706 * @cfg {Boolean} closable True if the panel can be closed/removed
36707 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36708 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36709 * @cfg {Toolbar} toolbar A toolbar for this panel
36710 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
36711 * @cfg {String} title The title for this panel
36712 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36713 * @cfg {String} url Calls {@link #setUrl} with this value
36714 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36715 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
36716 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
36717 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
36718 * @cfg {Boolean} badges render the badges
36721 * Create a new ContentPanel.
36722 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36723 * @param {String/Object} config A string to set only the title or a config object
36724 * @param {String} content (optional) Set the HTML content for this panel
36725 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36727 Roo.bootstrap.panel.Content = function( config){
36729 this.tpl = config.tpl || false;
36731 var el = config.el;
36732 var content = config.content;
36734 if(config.autoCreate){ // xtype is available if this is called from factory
36737 this.el = Roo.get(el);
36738 if(!this.el && config && config.autoCreate){
36739 if(typeof config.autoCreate == "object"){
36740 if(!config.autoCreate.id){
36741 config.autoCreate.id = config.id||el;
36743 this.el = Roo.DomHelper.append(document.body,
36744 config.autoCreate, true);
36746 var elcfg = { tag: "div",
36747 cls: "roo-layout-inactive-content",
36751 elcfg.html = config.html;
36755 this.el = Roo.DomHelper.append(document.body, elcfg , true);
36758 this.closable = false;
36759 this.loaded = false;
36760 this.active = false;
36763 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36765 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36767 this.wrapEl = this.el; //this.el.wrap();
36769 if (config.toolbar.items) {
36770 ti = config.toolbar.items ;
36771 delete config.toolbar.items ;
36775 this.toolbar.render(this.wrapEl, 'before');
36776 for(var i =0;i < ti.length;i++) {
36777 // Roo.log(['add child', items[i]]);
36778 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36780 this.toolbar.items = nitems;
36781 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36782 delete config.toolbar;
36786 // xtype created footer. - not sure if will work as we normally have to render first..
36787 if (this.footer && !this.footer.el && this.footer.xtype) {
36788 if (!this.wrapEl) {
36789 this.wrapEl = this.el.wrap();
36792 this.footer.container = this.wrapEl.createChild();
36794 this.footer = Roo.factory(this.footer, Roo);
36799 if(typeof config == "string"){
36800 this.title = config;
36802 Roo.apply(this, config);
36806 this.resizeEl = Roo.get(this.resizeEl, true);
36808 this.resizeEl = this.el;
36810 // handle view.xtype
36818 * Fires when this panel is activated.
36819 * @param {Roo.ContentPanel} this
36823 * @event deactivate
36824 * Fires when this panel is activated.
36825 * @param {Roo.ContentPanel} this
36827 "deactivate" : true,
36831 * Fires when this panel is resized if fitToFrame is true.
36832 * @param {Roo.ContentPanel} this
36833 * @param {Number} width The width after any component adjustments
36834 * @param {Number} height The height after any component adjustments
36840 * Fires when this tab is created
36841 * @param {Roo.ContentPanel} this
36852 if(this.autoScroll){
36853 this.resizeEl.setStyle("overflow", "auto");
36855 // fix randome scrolling
36856 //this.el.on('scroll', function() {
36857 // Roo.log('fix random scolling');
36858 // this.scrollTo('top',0);
36861 content = content || this.content;
36863 this.setContent(content);
36865 if(config && config.url){
36866 this.setUrl(this.url, this.params, this.loadOnce);
36871 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36873 if (this.view && typeof(this.view.xtype) != 'undefined') {
36874 this.view.el = this.el.appendChild(document.createElement("div"));
36875 this.view = Roo.factory(this.view);
36876 this.view.render && this.view.render(false, '');
36880 this.fireEvent('render', this);
36883 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36887 setRegion : function(region){
36888 this.region = region;
36889 this.setActiveClass(region && !this.background);
36893 setActiveClass: function(state)
36896 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36897 this.el.setStyle('position','relative');
36899 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36900 this.el.setStyle('position', 'absolute');
36905 * Returns the toolbar for this Panel if one was configured.
36906 * @return {Roo.Toolbar}
36908 getToolbar : function(){
36909 return this.toolbar;
36912 setActiveState : function(active)
36914 this.active = active;
36915 this.setActiveClass(active);
36917 if(this.fireEvent("deactivate", this) === false){
36922 this.fireEvent("activate", this);
36926 * Updates this panel's element
36927 * @param {String} content The new content
36928 * @param {Boolean} loadScripts (optional) true to look for and process scripts
36930 setContent : function(content, loadScripts){
36931 this.el.update(content, loadScripts);
36934 ignoreResize : function(w, h){
36935 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36938 this.lastSize = {width: w, height: h};
36943 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36944 * @return {Roo.UpdateManager} The UpdateManager
36946 getUpdateManager : function(){
36947 return this.el.getUpdateManager();
36950 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36951 * @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:
36954 url: "your-url.php",
36955 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36956 callback: yourFunction,
36957 scope: yourObject, //(optional scope)
36960 text: "Loading...",
36965 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
36966 * 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.
36967 * @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}
36968 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
36969 * @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.
36970 * @return {Roo.ContentPanel} this
36973 var um = this.el.getUpdateManager();
36974 um.update.apply(um, arguments);
36980 * 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.
36981 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
36982 * @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)
36983 * @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)
36984 * @return {Roo.UpdateManager} The UpdateManager
36986 setUrl : function(url, params, loadOnce){
36987 if(this.refreshDelegate){
36988 this.removeListener("activate", this.refreshDelegate);
36990 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
36991 this.on("activate", this.refreshDelegate);
36992 return this.el.getUpdateManager();
36995 _handleRefresh : function(url, params, loadOnce){
36996 if(!loadOnce || !this.loaded){
36997 var updater = this.el.getUpdateManager();
36998 updater.update(url, params, this._setLoaded.createDelegate(this));
37002 _setLoaded : function(){
37003 this.loaded = true;
37007 * Returns this panel's id
37010 getId : function(){
37015 * Returns this panel's element - used by regiosn to add.
37016 * @return {Roo.Element}
37018 getEl : function(){
37019 return this.wrapEl || this.el;
37024 adjustForComponents : function(width, height)
37026 //Roo.log('adjustForComponents ');
37027 if(this.resizeEl != this.el){
37028 width -= this.el.getFrameWidth('lr');
37029 height -= this.el.getFrameWidth('tb');
37032 var te = this.toolbar.getEl();
37033 te.setWidth(width);
37034 height -= te.getHeight();
37037 var te = this.footer.getEl();
37038 te.setWidth(width);
37039 height -= te.getHeight();
37043 if(this.adjustments){
37044 width += this.adjustments[0];
37045 height += this.adjustments[1];
37047 return {"width": width, "height": height};
37050 setSize : function(width, height){
37051 if(this.fitToFrame && !this.ignoreResize(width, height)){
37052 if(this.fitContainer && this.resizeEl != this.el){
37053 this.el.setSize(width, height);
37055 var size = this.adjustForComponents(width, height);
37056 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37057 this.fireEvent('resize', this, size.width, size.height);
37062 * Returns this panel's title
37065 getTitle : function(){
37067 if (typeof(this.title) != 'object') {
37072 for (var k in this.title) {
37073 if (!this.title.hasOwnProperty(k)) {
37077 if (k.indexOf('-') >= 0) {
37078 var s = k.split('-');
37079 for (var i = 0; i<s.length; i++) {
37080 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37083 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37090 * Set this panel's title
37091 * @param {String} title
37093 setTitle : function(title){
37094 this.title = title;
37096 this.region.updatePanelTitle(this, title);
37101 * Returns true is this panel was configured to be closable
37102 * @return {Boolean}
37104 isClosable : function(){
37105 return this.closable;
37108 beforeSlide : function(){
37110 this.resizeEl.clip();
37113 afterSlide : function(){
37115 this.resizeEl.unclip();
37119 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37120 * Will fail silently if the {@link #setUrl} method has not been called.
37121 * This does not activate the panel, just updates its content.
37123 refresh : function(){
37124 if(this.refreshDelegate){
37125 this.loaded = false;
37126 this.refreshDelegate();
37131 * Destroys this panel
37133 destroy : function(){
37134 this.el.removeAllListeners();
37135 var tempEl = document.createElement("span");
37136 tempEl.appendChild(this.el.dom);
37137 tempEl.innerHTML = "";
37143 * form - if the content panel contains a form - this is a reference to it.
37144 * @type {Roo.form.Form}
37148 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37149 * This contains a reference to it.
37155 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37165 * @param {Object} cfg Xtype definition of item to add.
37169 getChildContainer: function () {
37170 return this.getEl();
37175 var ret = new Roo.factory(cfg);
37180 if (cfg.xtype.match(/^Form$/)) {
37183 //if (this.footer) {
37184 // el = this.footer.container.insertSibling(false, 'before');
37186 el = this.el.createChild();
37189 this.form = new Roo.form.Form(cfg);
37192 if ( this.form.allItems.length) {
37193 this.form.render(el.dom);
37197 // should only have one of theses..
37198 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37199 // views.. should not be just added - used named prop 'view''
37201 cfg.el = this.el.appendChild(document.createElement("div"));
37204 var ret = new Roo.factory(cfg);
37206 ret.render && ret.render(false, ''); // render blank..
37216 * @class Roo.bootstrap.panel.Grid
37217 * @extends Roo.bootstrap.panel.Content
37219 * Create a new GridPanel.
37220 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37221 * @param {Object} config A the config object
37227 Roo.bootstrap.panel.Grid = function(config)
37231 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37232 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37234 config.el = this.wrapper;
37235 //this.el = this.wrapper;
37237 if (config.container) {
37238 // ctor'ed from a Border/panel.grid
37241 this.wrapper.setStyle("overflow", "hidden");
37242 this.wrapper.addClass('roo-grid-container');
37247 if(config.toolbar){
37248 var tool_el = this.wrapper.createChild();
37249 this.toolbar = Roo.factory(config.toolbar);
37251 if (config.toolbar.items) {
37252 ti = config.toolbar.items ;
37253 delete config.toolbar.items ;
37257 this.toolbar.render(tool_el);
37258 for(var i =0;i < ti.length;i++) {
37259 // Roo.log(['add child', items[i]]);
37260 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37262 this.toolbar.items = nitems;
37264 delete config.toolbar;
37267 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37268 config.grid.scrollBody = true;;
37269 config.grid.monitorWindowResize = false; // turn off autosizing
37270 config.grid.autoHeight = false;
37271 config.grid.autoWidth = false;
37273 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37275 if (config.background) {
37276 // render grid on panel activation (if panel background)
37277 this.on('activate', function(gp) {
37278 if (!gp.grid.rendered) {
37279 gp.grid.render(this.wrapper);
37280 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37285 this.grid.render(this.wrapper);
37286 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37289 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37290 // ??? needed ??? config.el = this.wrapper;
37295 // xtype created footer. - not sure if will work as we normally have to render first..
37296 if (this.footer && !this.footer.el && this.footer.xtype) {
37298 var ctr = this.grid.getView().getFooterPanel(true);
37299 this.footer.dataSource = this.grid.dataSource;
37300 this.footer = Roo.factory(this.footer, Roo);
37301 this.footer.render(ctr);
37311 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37312 getId : function(){
37313 return this.grid.id;
37317 * Returns the grid for this panel
37318 * @return {Roo.bootstrap.Table}
37320 getGrid : function(){
37324 setSize : function(width, height){
37325 if(!this.ignoreResize(width, height)){
37326 var grid = this.grid;
37327 var size = this.adjustForComponents(width, height);
37328 var gridel = grid.getGridEl();
37329 gridel.setSize(size.width, size.height);
37331 var thd = grid.getGridEl().select('thead',true).first();
37332 var tbd = grid.getGridEl().select('tbody', true).first();
37334 tbd.setSize(width, height - thd.getHeight());
37343 beforeSlide : function(){
37344 this.grid.getView().scroller.clip();
37347 afterSlide : function(){
37348 this.grid.getView().scroller.unclip();
37351 destroy : function(){
37352 this.grid.destroy();
37354 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37359 * @class Roo.bootstrap.panel.Nest
37360 * @extends Roo.bootstrap.panel.Content
37362 * Create a new Panel, that can contain a layout.Border.
37365 * @param {Roo.BorderLayout} layout The layout for this panel
37366 * @param {String/Object} config A string to set only the title or a config object
37368 Roo.bootstrap.panel.Nest = function(config)
37370 // construct with only one argument..
37371 /* FIXME - implement nicer consturctors
37372 if (layout.layout) {
37374 layout = config.layout;
37375 delete config.layout;
37377 if (layout.xtype && !layout.getEl) {
37378 // then layout needs constructing..
37379 layout = Roo.factory(layout, Roo);
37383 config.el = config.layout.getEl();
37385 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37387 config.layout.monitorWindowResize = false; // turn off autosizing
37388 this.layout = config.layout;
37389 this.layout.getEl().addClass("roo-layout-nested-layout");
37396 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37398 setSize : function(width, height){
37399 if(!this.ignoreResize(width, height)){
37400 var size = this.adjustForComponents(width, height);
37401 var el = this.layout.getEl();
37402 if (size.height < 1) {
37403 el.setWidth(size.width);
37405 el.setSize(size.width, size.height);
37407 var touch = el.dom.offsetWidth;
37408 this.layout.layout();
37409 // ie requires a double layout on the first pass
37410 if(Roo.isIE && !this.initialized){
37411 this.initialized = true;
37412 this.layout.layout();
37417 // activate all subpanels if not currently active..
37419 setActiveState : function(active){
37420 this.active = active;
37421 this.setActiveClass(active);
37424 this.fireEvent("deactivate", this);
37428 this.fireEvent("activate", this);
37429 // not sure if this should happen before or after..
37430 if (!this.layout) {
37431 return; // should not happen..
37434 for (var r in this.layout.regions) {
37435 reg = this.layout.getRegion(r);
37436 if (reg.getActivePanel()) {
37437 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37438 reg.setActivePanel(reg.getActivePanel());
37441 if (!reg.panels.length) {
37444 reg.showPanel(reg.getPanel(0));
37453 * Returns the nested BorderLayout for this panel
37454 * @return {Roo.BorderLayout}
37456 getLayout : function(){
37457 return this.layout;
37461 * Adds a xtype elements to the layout of the nested panel
37465 xtype : 'ContentPanel',
37472 xtype : 'NestedLayoutPanel',
37478 items : [ ... list of content panels or nested layout panels.. ]
37482 * @param {Object} cfg Xtype definition of item to add.
37484 addxtype : function(cfg) {
37485 return this.layout.addxtype(cfg);
37490 * Ext JS Library 1.1.1
37491 * Copyright(c) 2006-2007, Ext JS, LLC.
37493 * Originally Released Under LGPL - original licence link has changed is not relivant.
37496 * <script type="text/javascript">
37499 * @class Roo.TabPanel
37500 * @extends Roo.util.Observable
37501 * A lightweight tab container.
37505 // basic tabs 1, built from existing content
37506 var tabs = new Roo.TabPanel("tabs1");
37507 tabs.addTab("script", "View Script");
37508 tabs.addTab("markup", "View Markup");
37509 tabs.activate("script");
37511 // more advanced tabs, built from javascript
37512 var jtabs = new Roo.TabPanel("jtabs");
37513 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37515 // set up the UpdateManager
37516 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37517 var updater = tab2.getUpdateManager();
37518 updater.setDefaultUrl("ajax1.htm");
37519 tab2.on('activate', updater.refresh, updater, true);
37521 // Use setUrl for Ajax loading
37522 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37523 tab3.setUrl("ajax2.htm", null, true);
37526 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37529 jtabs.activate("jtabs-1");
37532 * Create a new TabPanel.
37533 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37534 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37536 Roo.bootstrap.panel.Tabs = function(config){
37538 * The container element for this TabPanel.
37539 * @type Roo.Element
37541 this.el = Roo.get(config.el);
37544 if(typeof config == "boolean"){
37545 this.tabPosition = config ? "bottom" : "top";
37547 Roo.apply(this, config);
37551 if(this.tabPosition == "bottom"){
37552 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37553 this.el.addClass("roo-tabs-bottom");
37555 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37556 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37557 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37559 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37561 if(this.tabPosition != "bottom"){
37562 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37563 * @type Roo.Element
37565 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37566 this.el.addClass("roo-tabs-top");
37570 this.bodyEl.setStyle("position", "relative");
37572 this.active = null;
37573 this.activateDelegate = this.activate.createDelegate(this);
37578 * Fires when the active tab changes
37579 * @param {Roo.TabPanel} this
37580 * @param {Roo.TabPanelItem} activePanel The new active tab
37584 * @event beforetabchange
37585 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37586 * @param {Roo.TabPanel} this
37587 * @param {Object} e Set cancel to true on this object to cancel the tab change
37588 * @param {Roo.TabPanelItem} tab The tab being changed to
37590 "beforetabchange" : true
37593 Roo.EventManager.onWindowResize(this.onResize, this);
37594 this.cpad = this.el.getPadding("lr");
37595 this.hiddenCount = 0;
37598 // toolbar on the tabbar support...
37599 if (this.toolbar) {
37600 alert("no toolbar support yet");
37601 this.toolbar = false;
37603 var tcfg = this.toolbar;
37604 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37605 this.toolbar = new Roo.Toolbar(tcfg);
37606 if (Roo.isSafari) {
37607 var tbl = tcfg.container.child('table', true);
37608 tbl.setAttribute('width', '100%');
37616 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37619 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37621 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37623 tabPosition : "top",
37625 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37627 currentTabWidth : 0,
37629 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37633 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37637 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37639 preferredTabWidth : 175,
37641 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37643 resizeTabs : false,
37645 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37647 monitorResize : true,
37649 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37654 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37655 * @param {String} id The id of the div to use <b>or create</b>
37656 * @param {String} text The text for the tab
37657 * @param {String} content (optional) Content to put in the TabPanelItem body
37658 * @param {Boolean} closable (optional) True to create a close icon on the tab
37659 * @return {Roo.TabPanelItem} The created TabPanelItem
37661 addTab : function(id, text, content, closable, tpl)
37663 var item = new Roo.bootstrap.panel.TabItem({
37667 closable : closable,
37670 this.addTabItem(item);
37672 item.setContent(content);
37678 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37679 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37680 * @return {Roo.TabPanelItem}
37682 getTab : function(id){
37683 return this.items[id];
37687 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37688 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37690 hideTab : function(id){
37691 var t = this.items[id];
37694 this.hiddenCount++;
37695 this.autoSizeTabs();
37700 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37701 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37703 unhideTab : function(id){
37704 var t = this.items[id];
37706 t.setHidden(false);
37707 this.hiddenCount--;
37708 this.autoSizeTabs();
37713 * Adds an existing {@link Roo.TabPanelItem}.
37714 * @param {Roo.TabPanelItem} item The TabPanelItem to add
37716 addTabItem : function(item){
37717 this.items[item.id] = item;
37718 this.items.push(item);
37719 // if(this.resizeTabs){
37720 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37721 // this.autoSizeTabs();
37723 // item.autoSize();
37728 * Removes a {@link Roo.TabPanelItem}.
37729 * @param {String/Number} id The id or index of the TabPanelItem to remove.
37731 removeTab : function(id){
37732 var items = this.items;
37733 var tab = items[id];
37734 if(!tab) { return; }
37735 var index = items.indexOf(tab);
37736 if(this.active == tab && items.length > 1){
37737 var newTab = this.getNextAvailable(index);
37742 this.stripEl.dom.removeChild(tab.pnode.dom);
37743 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37744 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37746 items.splice(index, 1);
37747 delete this.items[tab.id];
37748 tab.fireEvent("close", tab);
37749 tab.purgeListeners();
37750 this.autoSizeTabs();
37753 getNextAvailable : function(start){
37754 var items = this.items;
37756 // look for a next tab that will slide over to
37757 // replace the one being removed
37758 while(index < items.length){
37759 var item = items[++index];
37760 if(item && !item.isHidden()){
37764 // if one isn't found select the previous tab (on the left)
37767 var item = items[--index];
37768 if(item && !item.isHidden()){
37776 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37777 * @param {String/Number} id The id or index of the TabPanelItem to disable.
37779 disableTab : function(id){
37780 var tab = this.items[id];
37781 if(tab && this.active != tab){
37787 * Enables a {@link Roo.TabPanelItem} that is disabled.
37788 * @param {String/Number} id The id or index of the TabPanelItem to enable.
37790 enableTab : function(id){
37791 var tab = this.items[id];
37796 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37797 * @param {String/Number} id The id or index of the TabPanelItem to activate.
37798 * @return {Roo.TabPanelItem} The TabPanelItem.
37800 activate : function(id){
37801 var tab = this.items[id];
37805 if(tab == this.active || tab.disabled){
37809 this.fireEvent("beforetabchange", this, e, tab);
37810 if(e.cancel !== true && !tab.disabled){
37812 this.active.hide();
37814 this.active = this.items[id];
37815 this.active.show();
37816 this.fireEvent("tabchange", this, this.active);
37822 * Gets the active {@link Roo.TabPanelItem}.
37823 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37825 getActiveTab : function(){
37826 return this.active;
37830 * Updates the tab body element to fit the height of the container element
37831 * for overflow scrolling
37832 * @param {Number} targetHeight (optional) Override the starting height from the elements height
37834 syncHeight : function(targetHeight){
37835 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37836 var bm = this.bodyEl.getMargins();
37837 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37838 this.bodyEl.setHeight(newHeight);
37842 onResize : function(){
37843 if(this.monitorResize){
37844 this.autoSizeTabs();
37849 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37851 beginUpdate : function(){
37852 this.updating = true;
37856 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37858 endUpdate : function(){
37859 this.updating = false;
37860 this.autoSizeTabs();
37864 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37866 autoSizeTabs : function(){
37867 var count = this.items.length;
37868 var vcount = count - this.hiddenCount;
37869 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37872 var w = Math.max(this.el.getWidth() - this.cpad, 10);
37873 var availWidth = Math.floor(w / vcount);
37874 var b = this.stripBody;
37875 if(b.getWidth() > w){
37876 var tabs = this.items;
37877 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37878 if(availWidth < this.minTabWidth){
37879 /*if(!this.sleft){ // incomplete scrolling code
37880 this.createScrollButtons();
37883 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37886 if(this.currentTabWidth < this.preferredTabWidth){
37887 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37893 * Returns the number of tabs in this TabPanel.
37896 getCount : function(){
37897 return this.items.length;
37901 * Resizes all the tabs to the passed width
37902 * @param {Number} The new width
37904 setTabWidth : function(width){
37905 this.currentTabWidth = width;
37906 for(var i = 0, len = this.items.length; i < len; i++) {
37907 if(!this.items[i].isHidden()) {
37908 this.items[i].setWidth(width);
37914 * Destroys this TabPanel
37915 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37917 destroy : function(removeEl){
37918 Roo.EventManager.removeResizeListener(this.onResize, this);
37919 for(var i = 0, len = this.items.length; i < len; i++){
37920 this.items[i].purgeListeners();
37922 if(removeEl === true){
37923 this.el.update("");
37928 createStrip : function(container)
37930 var strip = document.createElement("nav");
37931 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37932 container.appendChild(strip);
37936 createStripList : function(strip)
37938 // div wrapper for retard IE
37939 // returns the "tr" element.
37940 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37941 //'<div class="x-tabs-strip-wrap">'+
37942 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37943 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37944 return strip.firstChild; //.firstChild.firstChild.firstChild;
37946 createBody : function(container)
37948 var body = document.createElement("div");
37949 Roo.id(body, "tab-body");
37950 //Roo.fly(body).addClass("x-tabs-body");
37951 Roo.fly(body).addClass("tab-content");
37952 container.appendChild(body);
37955 createItemBody :function(bodyEl, id){
37956 var body = Roo.getDom(id);
37958 body = document.createElement("div");
37961 //Roo.fly(body).addClass("x-tabs-item-body");
37962 Roo.fly(body).addClass("tab-pane");
37963 bodyEl.insertBefore(body, bodyEl.firstChild);
37967 createStripElements : function(stripEl, text, closable, tpl)
37969 var td = document.createElement("li"); // was td..
37972 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
37975 stripEl.appendChild(td);
37977 td.className = "x-tabs-closable";
37978 if(!this.closeTpl){
37979 this.closeTpl = new Roo.Template(
37980 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37981 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
37982 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
37985 var el = this.closeTpl.overwrite(td, {"text": text});
37986 var close = el.getElementsByTagName("div")[0];
37987 var inner = el.getElementsByTagName("em")[0];
37988 return {"el": el, "close": close, "inner": inner};
37991 // not sure what this is..
37992 // if(!this.tabTpl){
37993 //this.tabTpl = new Roo.Template(
37994 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
37995 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
37997 // this.tabTpl = new Roo.Template(
37998 // '<a href="#">' +
37999 // '<span unselectable="on"' +
38000 // (this.disableTooltips ? '' : ' title="{text}"') +
38001 // ' >{text}</span></a>'
38007 var template = tpl || this.tabTpl || false;
38011 template = new Roo.Template(
38013 '<span unselectable="on"' +
38014 (this.disableTooltips ? '' : ' title="{text}"') +
38015 ' >{text}</span></a>'
38019 switch (typeof(template)) {
38023 template = new Roo.Template(template);
38029 var el = template.overwrite(td, {"text": text});
38031 var inner = el.getElementsByTagName("span")[0];
38033 return {"el": el, "inner": inner};
38041 * @class Roo.TabPanelItem
38042 * @extends Roo.util.Observable
38043 * Represents an individual item (tab plus body) in a TabPanel.
38044 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38045 * @param {String} id The id of this TabPanelItem
38046 * @param {String} text The text for the tab of this TabPanelItem
38047 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38049 Roo.bootstrap.panel.TabItem = function(config){
38051 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38052 * @type Roo.TabPanel
38054 this.tabPanel = config.panel;
38056 * The id for this TabPanelItem
38059 this.id = config.id;
38061 this.disabled = false;
38063 this.text = config.text;
38065 this.loaded = false;
38066 this.closable = config.closable;
38069 * The body element for this TabPanelItem.
38070 * @type Roo.Element
38072 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38073 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38074 this.bodyEl.setStyle("display", "block");
38075 this.bodyEl.setStyle("zoom", "1");
38076 //this.hideAction();
38078 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38080 this.el = Roo.get(els.el);
38081 this.inner = Roo.get(els.inner, true);
38082 this.textEl = Roo.get(this.el.dom.firstChild, true);
38083 this.pnode = Roo.get(els.el.parentNode, true);
38084 // this.el.on("mousedown", this.onTabMouseDown, this);
38085 this.el.on("click", this.onTabClick, this);
38087 if(config.closable){
38088 var c = Roo.get(els.close, true);
38089 c.dom.title = this.closeText;
38090 c.addClassOnOver("close-over");
38091 c.on("click", this.closeClick, this);
38097 * Fires when this tab becomes the active tab.
38098 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38099 * @param {Roo.TabPanelItem} this
38103 * @event beforeclose
38104 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38105 * @param {Roo.TabPanelItem} this
38106 * @param {Object} e Set cancel to true on this object to cancel the close.
38108 "beforeclose": true,
38111 * Fires when this tab is closed.
38112 * @param {Roo.TabPanelItem} this
38116 * @event deactivate
38117 * Fires when this tab is no longer the active tab.
38118 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38119 * @param {Roo.TabPanelItem} this
38121 "deactivate" : true
38123 this.hidden = false;
38125 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38128 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38130 purgeListeners : function(){
38131 Roo.util.Observable.prototype.purgeListeners.call(this);
38132 this.el.removeAllListeners();
38135 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38138 this.pnode.addClass("active");
38141 this.tabPanel.stripWrap.repaint();
38143 this.fireEvent("activate", this.tabPanel, this);
38147 * Returns true if this tab is the active tab.
38148 * @return {Boolean}
38150 isActive : function(){
38151 return this.tabPanel.getActiveTab() == this;
38155 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38158 this.pnode.removeClass("active");
38160 this.fireEvent("deactivate", this.tabPanel, this);
38163 hideAction : function(){
38164 this.bodyEl.hide();
38165 this.bodyEl.setStyle("position", "absolute");
38166 this.bodyEl.setLeft("-20000px");
38167 this.bodyEl.setTop("-20000px");
38170 showAction : function(){
38171 this.bodyEl.setStyle("position", "relative");
38172 this.bodyEl.setTop("");
38173 this.bodyEl.setLeft("");
38174 this.bodyEl.show();
38178 * Set the tooltip for the tab.
38179 * @param {String} tooltip The tab's tooltip
38181 setTooltip : function(text){
38182 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38183 this.textEl.dom.qtip = text;
38184 this.textEl.dom.removeAttribute('title');
38186 this.textEl.dom.title = text;
38190 onTabClick : function(e){
38191 e.preventDefault();
38192 this.tabPanel.activate(this.id);
38195 onTabMouseDown : function(e){
38196 e.preventDefault();
38197 this.tabPanel.activate(this.id);
38200 getWidth : function(){
38201 return this.inner.getWidth();
38204 setWidth : function(width){
38205 var iwidth = width - this.pnode.getPadding("lr");
38206 this.inner.setWidth(iwidth);
38207 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38208 this.pnode.setWidth(width);
38212 * Show or hide the tab
38213 * @param {Boolean} hidden True to hide or false to show.
38215 setHidden : function(hidden){
38216 this.hidden = hidden;
38217 this.pnode.setStyle("display", hidden ? "none" : "");
38221 * Returns true if this tab is "hidden"
38222 * @return {Boolean}
38224 isHidden : function(){
38225 return this.hidden;
38229 * Returns the text for this tab
38232 getText : function(){
38236 autoSize : function(){
38237 //this.el.beginMeasure();
38238 this.textEl.setWidth(1);
38240 * #2804 [new] Tabs in Roojs
38241 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38243 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38244 //this.el.endMeasure();
38248 * Sets the text for the tab (Note: this also sets the tooltip text)
38249 * @param {String} text The tab's text and tooltip
38251 setText : function(text){
38253 this.textEl.update(text);
38254 this.setTooltip(text);
38255 //if(!this.tabPanel.resizeTabs){
38256 // this.autoSize();
38260 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38262 activate : function(){
38263 this.tabPanel.activate(this.id);
38267 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38269 disable : function(){
38270 if(this.tabPanel.active != this){
38271 this.disabled = true;
38272 this.pnode.addClass("disabled");
38277 * Enables this TabPanelItem if it was previously disabled.
38279 enable : function(){
38280 this.disabled = false;
38281 this.pnode.removeClass("disabled");
38285 * Sets the content for this TabPanelItem.
38286 * @param {String} content The content
38287 * @param {Boolean} loadScripts true to look for and load scripts
38289 setContent : function(content, loadScripts){
38290 this.bodyEl.update(content, loadScripts);
38294 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38295 * @return {Roo.UpdateManager} The UpdateManager
38297 getUpdateManager : function(){
38298 return this.bodyEl.getUpdateManager();
38302 * Set a URL to be used to load the content for this TabPanelItem.
38303 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38304 * @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)
38305 * @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)
38306 * @return {Roo.UpdateManager} The UpdateManager
38308 setUrl : function(url, params, loadOnce){
38309 if(this.refreshDelegate){
38310 this.un('activate', this.refreshDelegate);
38312 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38313 this.on("activate", this.refreshDelegate);
38314 return this.bodyEl.getUpdateManager();
38318 _handleRefresh : function(url, params, loadOnce){
38319 if(!loadOnce || !this.loaded){
38320 var updater = this.bodyEl.getUpdateManager();
38321 updater.update(url, params, this._setLoaded.createDelegate(this));
38326 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38327 * Will fail silently if the setUrl method has not been called.
38328 * This does not activate the panel, just updates its content.
38330 refresh : function(){
38331 if(this.refreshDelegate){
38332 this.loaded = false;
38333 this.refreshDelegate();
38338 _setLoaded : function(){
38339 this.loaded = true;
38343 closeClick : function(e){
38346 this.fireEvent("beforeclose", this, o);
38347 if(o.cancel !== true){
38348 this.tabPanel.removeTab(this.id);
38352 * The text displayed in the tooltip for the close icon.
38355 closeText : "Close this tab"
38358 * This script refer to:
38359 * Title: International Telephone Input
38360 * Author: Jack O'Connor
38361 * Code version: v12.1.12
38362 * Availability: https://github.com/jackocnr/intl-tel-input.git
38365 Roo.bootstrap.PhoneInputData = function() {
38368 "Afghanistan (افغانستان)",
38373 "Albania (Shqipëri)",
38378 "Algeria (الجزائر)",
38403 "Antigua and Barbuda",
38413 "Armenia (Հայաստան)",
38429 "Austria (Österreich)",
38434 "Azerbaijan (Azərbaycan)",
38444 "Bahrain (البحرين)",
38449 "Bangladesh (বাংলাদেশ)",
38459 "Belarus (Беларусь)",
38464 "Belgium (België)",
38494 "Bosnia and Herzegovina (Босна и Херцеговина)",
38509 "British Indian Ocean Territory",
38514 "British Virgin Islands",
38524 "Bulgaria (България)",
38534 "Burundi (Uburundi)",
38539 "Cambodia (កម្ពុជា)",
38544 "Cameroon (Cameroun)",
38553 ["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"]
38556 "Cape Verde (Kabu Verdi)",
38561 "Caribbean Netherlands",
38572 "Central African Republic (République centrafricaine)",
38592 "Christmas Island",
38598 "Cocos (Keeling) Islands",
38609 "Comoros (جزر القمر)",
38614 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38619 "Congo (Republic) (Congo-Brazzaville)",
38639 "Croatia (Hrvatska)",
38660 "Czech Republic (Česká republika)",
38665 "Denmark (Danmark)",
38680 "Dominican Republic (República Dominicana)",
38684 ["809", "829", "849"]
38702 "Equatorial Guinea (Guinea Ecuatorial)",
38722 "Falkland Islands (Islas Malvinas)",
38727 "Faroe Islands (Føroyar)",
38748 "French Guiana (Guyane française)",
38753 "French Polynesia (Polynésie française)",
38768 "Georgia (საქართველო)",
38773 "Germany (Deutschland)",
38793 "Greenland (Kalaallit Nunaat)",
38830 "Guinea-Bissau (Guiné Bissau)",
38855 "Hungary (Magyarország)",
38860 "Iceland (Ísland)",
38880 "Iraq (العراق)",
38896 "Israel (ישראל)",
38923 "Jordan (الأردن)",
38928 "Kazakhstan (Казахстан)",
38949 "Kuwait (الكويت)",
38954 "Kyrgyzstan (Кыргызстан)",
38964 "Latvia (Latvija)",
38969 "Lebanon (لبنان)",
38984 "Libya (ليبيا)",
38994 "Lithuania (Lietuva)",
39009 "Macedonia (FYROM) (Македонија)",
39014 "Madagascar (Madagasikara)",
39044 "Marshall Islands",
39054 "Mauritania (موريتانيا)",
39059 "Mauritius (Moris)",
39080 "Moldova (Republica Moldova)",
39090 "Mongolia (Монгол)",
39095 "Montenegro (Crna Gora)",
39105 "Morocco (المغرب)",
39111 "Mozambique (Moçambique)",
39116 "Myanmar (Burma) (မြန်မာ)",
39121 "Namibia (Namibië)",
39136 "Netherlands (Nederland)",
39141 "New Caledonia (Nouvelle-Calédonie)",
39176 "North Korea (조선 민주주의 인민 공화국)",
39181 "Northern Mariana Islands",
39197 "Pakistan (پاکستان)",
39207 "Palestine (فلسطين)",
39217 "Papua New Guinea",
39259 "Réunion (La Réunion)",
39265 "Romania (România)",
39281 "Saint Barthélemy",
39292 "Saint Kitts and Nevis",
39302 "Saint Martin (Saint-Martin (partie française))",
39308 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39313 "Saint Vincent and the Grenadines",
39328 "São Tomé and Príncipe (São Tomé e Príncipe)",
39333 "Saudi Arabia (المملكة العربية السعودية)",
39338 "Senegal (Sénégal)",
39368 "Slovakia (Slovensko)",
39373 "Slovenia (Slovenija)",
39383 "Somalia (Soomaaliya)",
39393 "South Korea (대한민국)",
39398 "South Sudan (جنوب السودان)",
39408 "Sri Lanka (ශ්රී ලංකාව)",
39413 "Sudan (السودان)",
39423 "Svalbard and Jan Mayen",
39434 "Sweden (Sverige)",
39439 "Switzerland (Schweiz)",
39444 "Syria (سوريا)",
39489 "Trinidad and Tobago",
39494 "Tunisia (تونس)",
39499 "Turkey (Türkiye)",
39509 "Turks and Caicos Islands",
39519 "U.S. Virgin Islands",
39529 "Ukraine (Україна)",
39534 "United Arab Emirates (الإمارات العربية المتحدة)",
39556 "Uzbekistan (Oʻzbekiston)",
39566 "Vatican City (Città del Vaticano)",
39577 "Vietnam (Việt Nam)",
39582 "Wallis and Futuna (Wallis-et-Futuna)",
39587 "Western Sahara (الصحراء الغربية)",
39593 "Yemen (اليمن)",
39617 * This script refer to:
39618 * Title: International Telephone Input
39619 * Author: Jack O'Connor
39620 * Code version: v12.1.12
39621 * Availability: https://github.com/jackocnr/intl-tel-input.git
39625 * @class Roo.bootstrap.PhoneInput
39626 * @extends Roo.bootstrap.TriggerField
39627 * An input with International dial-code selection
39629 * @cfg {String} defaultDialCode default '+852'
39630 * @cfg {Array} preferedCountries default []
39633 * Create a new PhoneInput.
39634 * @param {Object} config Configuration options
39637 Roo.bootstrap.PhoneInput = function(config) {
39638 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39641 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39643 listWidth: undefined,
39645 selectedClass: 'active',
39647 invalidClass : "has-warning",
39649 validClass: 'has-success',
39651 allowed: '0123456789',
39654 * @cfg {String} defaultDialCode The default dial code when initializing the input
39656 defaultDialCode: '+852',
39659 * @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
39661 preferedCountries: false,
39663 getAutoCreate : function()
39665 var data = Roo.bootstrap.PhoneInputData();
39666 var align = this.labelAlign || this.parentLabelAlign();
39669 this.allCountries = [];
39670 this.dialCodeMapping = [];
39672 for (var i = 0; i < data.length; i++) {
39674 this.allCountries[i] = {
39678 priority: c[3] || 0,
39679 areaCodes: c[4] || null
39681 this.dialCodeMapping[c[2]] = {
39684 priority: c[3] || 0,
39685 areaCodes: c[4] || null
39697 cls : 'form-control tel-input',
39698 autocomplete: 'new-password'
39701 var hiddenInput = {
39704 cls: 'hidden-tel-input'
39708 hiddenInput.name = this.name;
39711 if (this.disabled) {
39712 input.disabled = true;
39715 var flag_container = {
39732 cls: this.hasFeedback ? 'has-feedback' : '',
39738 cls: 'dial-code-holder',
39745 cls: 'roo-select2-container input-group',
39752 if (this.fieldLabel.length) {
39755 tooltip: 'This field is required'
39761 cls: 'control-label',
39767 html: this.fieldLabel
39770 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39776 if(this.indicatorpos == 'right') {
39777 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39784 if(align == 'left') {
39792 if(this.labelWidth > 12){
39793 label.style = "width: " + this.labelWidth + 'px';
39795 if(this.labelWidth < 13 && this.labelmd == 0){
39796 this.labelmd = this.labelWidth;
39798 if(this.labellg > 0){
39799 label.cls += ' col-lg-' + this.labellg;
39800 input.cls += ' col-lg-' + (12 - this.labellg);
39802 if(this.labelmd > 0){
39803 label.cls += ' col-md-' + this.labelmd;
39804 container.cls += ' col-md-' + (12 - this.labelmd);
39806 if(this.labelsm > 0){
39807 label.cls += ' col-sm-' + this.labelsm;
39808 container.cls += ' col-sm-' + (12 - this.labelsm);
39810 if(this.labelxs > 0){
39811 label.cls += ' col-xs-' + this.labelxs;
39812 container.cls += ' col-xs-' + (12 - this.labelxs);
39822 var settings = this;
39824 ['xs','sm','md','lg'].map(function(size){
39825 if (settings[size]) {
39826 cfg.cls += ' col-' + size + '-' + settings[size];
39830 this.store = new Roo.data.Store({
39831 proxy : new Roo.data.MemoryProxy({}),
39832 reader : new Roo.data.JsonReader({
39843 'name' : 'dialCode',
39847 'name' : 'priority',
39851 'name' : 'areaCodes',
39858 if(!this.preferedCountries) {
39859 this.preferedCountries = [
39866 var p = this.preferedCountries.reverse();
39869 for (var i = 0; i < p.length; i++) {
39870 for (var j = 0; j < this.allCountries.length; j++) {
39871 if(this.allCountries[j].iso2 == p[i]) {
39872 var t = this.allCountries[j];
39873 this.allCountries.splice(j,1);
39874 this.allCountries.unshift(t);
39880 this.store.proxy.data = {
39882 data: this.allCountries
39888 initEvents : function()
39891 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39893 this.indicator = this.indicatorEl();
39894 this.flag = this.flagEl();
39895 this.dialCodeHolder = this.dialCodeHolderEl();
39897 this.trigger = this.el.select('div.flag-box',true).first();
39898 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39903 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39904 _this.list.setWidth(lw);
39907 this.list.on('mouseover', this.onViewOver, this);
39908 this.list.on('mousemove', this.onViewMove, this);
39909 this.inputEl().on("keyup", this.onKeyUp, this);
39911 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39913 this.view = new Roo.View(this.list, this.tpl, {
39914 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39917 this.view.on('click', this.onViewClick, this);
39918 this.setValue(this.defaultDialCode);
39921 onTriggerClick : function(e)
39923 Roo.log('trigger click');
39928 if(this.isExpanded()){
39930 this.hasFocus = false;
39932 this.store.load({});
39933 this.hasFocus = true;
39938 isExpanded : function()
39940 return this.list.isVisible();
39943 collapse : function()
39945 if(!this.isExpanded()){
39949 Roo.get(document).un('mousedown', this.collapseIf, this);
39950 Roo.get(document).un('mousewheel', this.collapseIf, this);
39951 this.fireEvent('collapse', this);
39955 expand : function()
39959 if(this.isExpanded() || !this.hasFocus){
39963 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
39964 this.list.setWidth(lw);
39967 this.restrictHeight();
39969 Roo.get(document).on('mousedown', this.collapseIf, this);
39970 Roo.get(document).on('mousewheel', this.collapseIf, this);
39972 this.fireEvent('expand', this);
39975 restrictHeight : function()
39977 this.list.alignTo(this.inputEl(), this.listAlign);
39978 this.list.alignTo(this.inputEl(), this.listAlign);
39981 onViewOver : function(e, t)
39983 if(this.inKeyMode){
39986 var item = this.view.findItemFromChild(t);
39989 var index = this.view.indexOf(item);
39990 this.select(index, false);
39995 onViewClick : function(view, doFocus, el, e)
39997 var index = this.view.getSelectedIndexes()[0];
39999 var r = this.store.getAt(index);
40002 this.onSelect(r, index);
40004 if(doFocus !== false && !this.blockFocus){
40005 this.inputEl().focus();
40009 onViewMove : function(e, t)
40011 this.inKeyMode = false;
40014 select : function(index, scrollIntoView)
40016 this.selectedIndex = index;
40017 this.view.select(index);
40018 if(scrollIntoView !== false){
40019 var el = this.view.getNode(index);
40021 this.list.scrollChildIntoView(el, false);
40026 createList : function()
40028 this.list = Roo.get(document.body).createChild({
40030 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40031 style: 'display:none'
40033 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
40036 collapseIf : function(e)
40038 var in_combo = e.within(this.el);
40039 var in_list = e.within(this.list);
40040 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40042 if (in_combo || in_list || is_list) {
40048 onSelect : function(record, index)
40050 if(this.fireEvent('beforeselect', this, record, index) !== false){
40052 this.setFlagClass(record.data.iso2);
40053 this.setDialCode(record.data.dialCode);
40054 this.hasFocus = false;
40056 this.fireEvent('select', this, record, index);
40060 flagEl : function()
40062 var flag = this.el.select('div.flag',true).first();
40069 dialCodeHolderEl : function()
40071 var d = this.el.select('input.dial-code-holder',true).first();
40078 setDialCode : function(v)
40080 this.dialCodeHolder.dom.value = '+'+v;
40083 setFlagClass : function(n)
40085 this.flag.dom.className = 'flag '+n;
40088 getValue : function()
40090 var v = this.inputEl().getValue();
40091 if(this.dialCodeHolder) {
40092 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40097 setValue : function(v)
40099 var d = this.getDialCode(v);
40101 //invalid dial code
40102 if(v.length == 0 || !d || d.length == 0) {
40104 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40105 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40111 this.setFlagClass(this.dialCodeMapping[d].iso2);
40112 this.setDialCode(d);
40113 this.inputEl().dom.value = v.replace('+'+d,'');
40114 this.hiddenEl().dom.value = this.getValue();
40119 getDialCode : function(v = '')
40121 if (v.length == 0) {
40122 return this.dialCodeHolder.dom.value;
40126 if (v.charAt(0) != "+") {
40129 var numericChars = "";
40130 for (var i = 1; i < v.length; i++) {
40131 var c = v.charAt(i);
40134 if (this.dialCodeMapping[numericChars]) {
40135 dialCode = v.substr(1, i);
40137 if (numericChars.length == 4) {
40147 this.setValue(this.defaultDialCode);
40151 hiddenEl : function()
40153 return this.el.select('input.hidden-tel-input',true).first();
40156 onKeyUp : function(e){
40158 var k = e.getKey();
40159 var c = e.getCharCode();
40162 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40163 this.allowed.indexOf(String.fromCharCode(c)) === -1
40168 // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40171 if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40175 this.setValue(this.getValue());
40180 * @class Roo.bootstrap.MoneyField
40181 * @extends Roo.bootstrap.ComboBox
40182 * Bootstrap MoneyField class
40185 * Create a new MoneyField.
40186 * @param {Object} config Configuration options
40189 Roo.bootstrap.MoneyField = function(config) {
40191 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40195 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40198 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40200 allowDecimals : true,
40202 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40204 decimalSeparator : ".",
40206 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40208 decimalPrecision : 0,
40210 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40212 allowNegative : true,
40214 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40216 minValue : Number.NEGATIVE_INFINITY,
40218 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40220 maxValue : Number.MAX_VALUE,
40222 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40224 minText : "The minimum value for this field is {0}",
40226 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40228 maxText : "The maximum value for this field is {0}",
40230 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40231 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40233 nanText : "{0} is not a valid number",
40235 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40239 * @cfg {String} defaults currency of the MoneyField
40240 * value should be in lkey
40242 defaultCurrency : false,
40244 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40246 thousandsDelimiter : false,
40256 getAutoCreate : function()
40258 var align = this.labelAlign || this.parentLabelAlign();
40270 cls : 'form-control roo-money-amount-input',
40271 autocomplete: 'new-password'
40274 var hiddenInput = {
40278 cls: 'hidden-number-input'
40282 hiddenInput.name = this.name;
40285 if (this.disabled) {
40286 input.disabled = true;
40289 var clg = 12 - this.inputlg;
40290 var cmd = 12 - this.inputmd;
40291 var csm = 12 - this.inputsm;
40292 var cxs = 12 - this.inputxs;
40296 cls : 'row roo-money-field',
40300 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40304 cls: 'roo-select2-container input-group',
40308 cls : 'form-control roo-money-currency-input',
40309 autocomplete: 'new-password',
40311 name : this.currencyName
40315 cls : 'input-group-addon',
40329 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40333 cls: this.hasFeedback ? 'has-feedback' : '',
40344 if (this.fieldLabel.length) {
40347 tooltip: 'This field is required'
40353 cls: 'control-label',
40359 html: this.fieldLabel
40362 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40368 if(this.indicatorpos == 'right') {
40369 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40376 if(align == 'left') {
40384 if(this.labelWidth > 12){
40385 label.style = "width: " + this.labelWidth + 'px';
40387 if(this.labelWidth < 13 && this.labelmd == 0){
40388 this.labelmd = this.labelWidth;
40390 if(this.labellg > 0){
40391 label.cls += ' col-lg-' + this.labellg;
40392 input.cls += ' col-lg-' + (12 - this.labellg);
40394 if(this.labelmd > 0){
40395 label.cls += ' col-md-' + this.labelmd;
40396 container.cls += ' col-md-' + (12 - this.labelmd);
40398 if(this.labelsm > 0){
40399 label.cls += ' col-sm-' + this.labelsm;
40400 container.cls += ' col-sm-' + (12 - this.labelsm);
40402 if(this.labelxs > 0){
40403 label.cls += ' col-xs-' + this.labelxs;
40404 container.cls += ' col-xs-' + (12 - this.labelxs);
40415 var settings = this;
40417 ['xs','sm','md','lg'].map(function(size){
40418 if (settings[size]) {
40419 cfg.cls += ' col-' + size + '-' + settings[size];
40426 initEvents : function()
40428 this.indicator = this.indicatorEl();
40430 this.initCurrencyEvent();
40432 this.initNumberEvent();
40435 initCurrencyEvent : function()
40438 throw "can not find store for combo";
40441 this.store = Roo.factory(this.store, Roo.data);
40442 this.store.parent = this;
40446 this.triggerEl = this.el.select('.input-group-addon', true).first();
40448 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40453 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40454 _this.list.setWidth(lw);
40457 this.list.on('mouseover', this.onViewOver, this);
40458 this.list.on('mousemove', this.onViewMove, this);
40459 this.list.on('scroll', this.onViewScroll, this);
40462 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40465 this.view = new Roo.View(this.list, this.tpl, {
40466 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40469 this.view.on('click', this.onViewClick, this);
40471 this.store.on('beforeload', this.onBeforeLoad, this);
40472 this.store.on('load', this.onLoad, this);
40473 this.store.on('loadexception', this.onLoadException, this);
40475 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40476 "up" : function(e){
40477 this.inKeyMode = true;
40481 "down" : function(e){
40482 if(!this.isExpanded()){
40483 this.onTriggerClick();
40485 this.inKeyMode = true;
40490 "enter" : function(e){
40493 if(this.fireEvent("specialkey", this, e)){
40494 this.onViewClick(false);
40500 "esc" : function(e){
40504 "tab" : function(e){
40507 if(this.fireEvent("specialkey", this, e)){
40508 this.onViewClick(false);
40516 doRelay : function(foo, bar, hname){
40517 if(hname == 'down' || this.scope.isExpanded()){
40518 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40526 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40530 initNumberEvent : function(e)
40532 this.inputEl().on("keydown" , this.fireKey, this);
40533 this.inputEl().on("focus", this.onFocus, this);
40534 this.inputEl().on("blur", this.onBlur, this);
40536 this.inputEl().relayEvent('keyup', this);
40538 if(this.indicator){
40539 this.indicator.addClass('invisible');
40542 this.originalValue = this.getValue();
40544 if(this.validationEvent == 'keyup'){
40545 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40546 this.inputEl().on('keyup', this.filterValidation, this);
40548 else if(this.validationEvent !== false){
40549 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40552 if(this.selectOnFocus){
40553 this.on("focus", this.preFocus, this);
40556 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40557 this.inputEl().on("keypress", this.filterKeys, this);
40559 this.inputEl().relayEvent('keypress', this);
40562 var allowed = "0123456789";
40564 if(this.allowDecimals){
40565 allowed += this.decimalSeparator;
40568 if(this.allowNegative){
40572 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40574 var keyPress = function(e){
40576 var k = e.getKey();
40578 var c = e.getCharCode();
40581 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40582 allowed.indexOf(String.fromCharCode(c)) === -1
40588 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40592 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40597 this.inputEl().on("keypress", keyPress, this);
40601 onTriggerClick : function(e)
40608 this.loadNext = false;
40610 if(this.isExpanded()){
40615 this.hasFocus = true;
40617 if(this.triggerAction == 'all') {
40618 this.doQuery(this.allQuery, true);
40622 this.doQuery(this.getRawValue());
40625 getCurrency : function()
40627 var v = this.currencyEl().getValue();
40632 restrictHeight : function()
40634 this.list.alignTo(this.currencyEl(), this.listAlign);
40635 this.list.alignTo(this.currencyEl(), this.listAlign);
40638 onViewClick : function(view, doFocus, el, e)
40640 var index = this.view.getSelectedIndexes()[0];
40642 var r = this.store.getAt(index);
40645 this.onSelect(r, index);
40649 onSelect : function(record, index){
40651 if(this.fireEvent('beforeselect', this, record, index) !== false){
40653 this.setFromCurrencyData(index > -1 ? record.data : false);
40657 this.fireEvent('select', this, record, index);
40661 setFromCurrencyData : function(o)
40665 this.lastCurrency = o;
40667 if (this.currencyField) {
40668 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40670 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40673 this.lastSelectionText = currency;
40675 //setting default currency
40676 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40677 this.setCurrency(this.defaultCurrency);
40681 this.setCurrency(currency);
40684 setFromData : function(o)
40688 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40690 this.setFromCurrencyData(c);
40695 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40697 Roo.log('no value set for '+ (this.name ? this.name : this.id));
40700 this.setValue(value);
40704 setCurrency : function(v)
40706 this.currencyValue = v;
40709 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40714 setValue : function(v)
40716 v = this.fixPrecision(v);
40718 v = String(v).replace(".", this.decimalSeparator);
40724 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40726 this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision,
40727 this.thousandsDelimiter || ','
40730 if(this.allowBlank && !v) {
40731 this.inputEl().dom.value = '';
40738 getRawValue : function()
40740 var v = this.inputEl().getValue();
40745 getValue : function()
40747 return this.fixPrecision(this.parseValue(this.getRawValue()));
40750 parseValue : function(value)
40752 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40753 return isNaN(value) ? '' : value;
40756 fixPrecision : function(value)
40758 var nan = isNaN(value);
40760 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40761 return nan ? '' : value;
40764 return parseFloat(value).toFixed(this.decimalPrecision);
40767 decimalPrecisionFcn : function(v)
40769 return Math.floor(v);
40772 validateValue : function(value)
40774 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40778 var num = this.parseValue(value);
40781 this.markInvalid(String.format(this.nanText, value));
40785 if(num < this.minValue){
40786 this.markInvalid(String.format(this.minText, this.minValue));
40790 if(num > this.maxValue){
40791 this.markInvalid(String.format(this.maxText, this.maxValue));
40798 validate : function()
40800 if(this.disabled || this.allowBlank){
40805 var currency = this.getCurrency();
40807 if(this.validateValue(this.getRawValue()) && currency.length){
40812 this.markInvalid();
40816 getName: function()
40821 beforeBlur : function()
40827 var v = this.parseValue(this.getRawValue());
40834 onBlur : function()
40838 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40839 //this.el.removeClass(this.focusClass);
40842 this.hasFocus = false;
40844 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40848 var v = this.getValue();
40850 if(String(v) !== String(this.startValue)){
40851 this.fireEvent('change', this, v, this.startValue);
40854 this.fireEvent("blur", this);
40857 inputEl : function()
40859 return this.el.select('.roo-money-amount-input', true).first();
40862 currencyEl : function()
40864 return this.el.select('.roo-money-currency-input', true).first();
40867 hiddenEl : function()
40869 return this.el.select('input.hidden-number-input',true).first();