2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass('hidden');
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass('hidden');
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @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)
593 * @cfg {String} badge text for badge
594 * @cfg {String} theme (default|glow)
595 * @cfg {Boolean} inverse dark themed version
596 * @cfg {Boolean} toggle is it a slidy toggle button
597 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
598 * @cfg {String} ontext text for on slidy toggle state
599 * @cfg {String} offtext text for off slidy toggle state
600 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
601 * @cfg {Boolean} removeClass remove the standard class..
602 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
605 * Create a new button
606 * @param {Object} config The config object
610 Roo.bootstrap.Button = function(config){
611 Roo.bootstrap.Button.superclass.constructor.call(this, config);
612 this.weightClass = ["btn-default btn-outline-secondary",
624 * When a butotn is pressed
625 * @param {Roo.bootstrap.Button} btn
626 * @param {Roo.EventObject} e
631 * After the button has been toggles
632 * @param {Roo.bootstrap.Button} btn
633 * @param {Roo.EventObject} e
634 * @param {boolean} pressed (also available as button.pressed)
640 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
660 preventDefault: true,
668 getAutoCreate : function(){
676 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
677 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
682 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
684 if (this.toggle == true) {
687 cls: 'slider-frame roo-button',
692 'data-off-text':'OFF',
693 cls: 'slider-button',
699 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
700 cfg.cls += ' '+this.weight;
709 cfg["aria-hidden"] = true;
711 cfg.html = "×";
717 if (this.theme==='default') {
718 cfg.cls = 'btn roo-button';
720 //if (this.parentType != 'Navbar') {
721 this.weight = this.weight.length ? this.weight : 'default';
723 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
725 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
726 var weight = this.weight == 'default' ? 'secondary' : this.weight;
727 cfg.cls += ' btn-' + outline + weight;
728 if (this.weight == 'default') {
730 cfg.cls += ' btn-' + this.weight;
733 } else if (this.theme==='glow') {
736 cfg.cls = 'btn-glow roo-button';
738 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
740 cfg.cls += ' ' + this.weight;
746 this.cls += ' inverse';
750 if (this.active || this.pressed === true) {
751 cfg.cls += ' active';
755 cfg.disabled = 'disabled';
759 Roo.log('changing to ul' );
761 this.glyphicon = 'caret';
764 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
766 //gsRoo.log(this.parentType);
767 if (this.parentType === 'Navbar' && !this.parent().bar) {
768 Roo.log('changing to li?');
777 href : this.href || '#'
780 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
781 cfg.cls += ' dropdown';
788 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
790 if (this.glyphicon) {
791 cfg.html = ' ' + cfg.html;
796 cls: 'glyphicon glyphicon-' + this.glyphicon
806 // cfg.cls='btn roo-button';
810 var value = cfg.html;
815 cls: 'glyphicon glyphicon-' + this.glyphicon,
820 var bw = this.badge_weight.length ? this.badge_weight :
821 (this.weight.length ? this.weight : 'secondary');
822 bw = bw == 'default' ? 'secondary' : bw;
828 cls: 'badge badge-' + bw,
837 cfg.cls += ' dropdown';
838 cfg.html = typeof(cfg.html) != 'undefined' ?
839 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
842 if (cfg.tag !== 'a' && this.href !== '') {
843 throw "Tag must be a to set href.";
844 } else if (this.href.length > 0) {
845 cfg.href = this.href;
848 if(this.removeClass){
853 cfg.target = this.target;
858 initEvents: function() {
859 // Roo.log('init events?');
860 // Roo.log(this.el.dom);
863 if (typeof (this.menu) != 'undefined') {
864 this.menu.parentType = this.xtype;
865 this.menu.triggerEl = this.el;
866 this.addxtype(Roo.apply({}, this.menu));
870 if (this.el.hasClass('roo-button')) {
871 this.el.on('click', this.onClick, this);
873 this.el.select('.roo-button').on('click', this.onClick, this);
876 if(this.removeClass){
877 this.el.on('click', this.onClick, this);
880 this.el.enableDisplayMode();
883 onClick : function(e)
889 Roo.log('button on click ');
890 if(this.preventDefault){
894 if (this.pressed === true || this.pressed === false) {
895 this.toggleActive(e);
899 this.fireEvent('click', this, e);
903 * Enables this button
907 this.disabled = false;
908 this.el.removeClass('disabled');
912 * Disable this button
916 this.disabled = true;
917 this.el.addClass('disabled');
920 * sets the active state on/off,
921 * @param {Boolean} state (optional) Force a particular state
923 setActive : function(v) {
925 this.el[v ? 'addClass' : 'removeClass']('active');
929 * toggles the current active state
931 toggleActive : function(e)
933 this.setActive(!this.pressed);
934 this.fireEvent('toggle', this, e, !this.pressed);
937 * get the current active state
938 * @return {boolean} true if it's active
940 isActive : function()
942 return this.el.hasClass('active');
945 * set the text of the first selected button
947 setText : function(str)
949 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
952 * get the text of the first selected button
956 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
959 setWeight : function(str)
961 this.el.removeClass(this.weightClass);
963 var outline = this.outline ? 'outline-' : '';
964 if (str == 'default') {
965 this.el.addClass('btn-default btn-outline-secondary');
968 this.el.addClass('btn-' + outline + str);
982 * @class Roo.bootstrap.Column
983 * @extends Roo.bootstrap.Component
984 * Bootstrap Column class
985 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
986 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
987 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
988 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
989 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
990 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
991 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
992 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
995 * @cfg {Boolean} hidden (true|false) hide the element
996 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
997 * @cfg {String} fa (ban|check|...) font awesome icon
998 * @cfg {Number} fasize (1|2|....) font awsome size
1000 * @cfg {String} icon (info-sign|check|...) glyphicon name
1002 * @cfg {String} html content of column.
1005 * Create a new Column
1006 * @param {Object} config The config object
1009 Roo.bootstrap.Column = function(config){
1010 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1013 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1031 getAutoCreate : function(){
1032 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1040 ['xs','sm','md','lg'].map(function(size){
1041 //Roo.log( size + ':' + settings[size]);
1043 if (settings[size+'off'] !== false) {
1044 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1047 if (settings[size] === false) {
1051 if (!settings[size]) { // 0 = hidden
1052 cfg.cls += ' hidden-' + size;
1055 cfg.cls += ' col-' + size + '-' + settings[size];
1060 cfg.cls += ' hidden';
1063 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1064 cfg.cls +=' alert alert-' + this.alert;
1068 if (this.html.length) {
1069 cfg.html = this.html;
1073 if (this.fasize > 1) {
1074 fasize = ' fa-' + this.fasize + 'x';
1076 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1081 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1100 * @class Roo.bootstrap.Container
1101 * @extends Roo.bootstrap.Component
1102 * Bootstrap Container class
1103 * @cfg {Boolean} jumbotron is it a jumbotron element
1104 * @cfg {String} html content of element
1105 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1106 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1107 * @cfg {String} header content of header (for panel)
1108 * @cfg {String} footer content of footer (for panel)
1109 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1110 * @cfg {String} tag (header|aside|section) type of HTML tag.
1111 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1112 * @cfg {String} fa font awesome icon
1113 * @cfg {String} icon (info-sign|check|...) glyphicon name
1114 * @cfg {Boolean} hidden (true|false) hide the element
1115 * @cfg {Boolean} expandable (true|false) default false
1116 * @cfg {Boolean} expanded (true|false) default true
1117 * @cfg {String} rheader contet on the right of header
1118 * @cfg {Boolean} clickable (true|false) default false
1122 * Create a new Container
1123 * @param {Object} config The config object
1126 Roo.bootstrap.Container = function(config){
1127 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1133 * After the panel has been expand
1135 * @param {Roo.bootstrap.Container} this
1140 * After the panel has been collapsed
1142 * @param {Roo.bootstrap.Container} this
1147 * When a element is chick
1148 * @param {Roo.bootstrap.Container} this
1149 * @param {Roo.EventObject} e
1155 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1173 getChildContainer : function() {
1179 if (this.panel.length) {
1180 return this.el.select('.panel-body',true).first();
1187 getAutoCreate : function(){
1190 tag : this.tag || 'div',
1194 if (this.jumbotron) {
1195 cfg.cls = 'jumbotron';
1200 // - this is applied by the parent..
1202 // cfg.cls = this.cls + '';
1205 if (this.sticky.length) {
1207 var bd = Roo.get(document.body);
1208 if (!bd.hasClass('bootstrap-sticky')) {
1209 bd.addClass('bootstrap-sticky');
1210 Roo.select('html',true).setStyle('height', '100%');
1213 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1217 if (this.well.length) {
1218 switch (this.well) {
1221 cfg.cls +=' well well-' +this.well;
1230 cfg.cls += ' hidden';
1234 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1235 cfg.cls +=' alert alert-' + this.alert;
1240 if (this.panel.length) {
1241 cfg.cls += ' panel panel-' + this.panel;
1243 if (this.header.length) {
1247 if(this.expandable){
1249 cfg.cls = cfg.cls + ' expandable';
1253 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1261 cls : 'panel-title',
1262 html : (this.expandable ? ' ' : '') + this.header
1266 cls: 'panel-header-right',
1272 cls : 'panel-heading',
1273 style : this.expandable ? 'cursor: pointer' : '',
1281 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1286 if (this.footer.length) {
1288 cls : 'panel-footer',
1297 body.html = this.html || cfg.html;
1298 // prefix with the icons..
1300 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1303 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1308 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1309 cfg.cls = 'container';
1315 initEvents: function()
1317 if(this.expandable){
1318 var headerEl = this.headerEl();
1321 headerEl.on('click', this.onToggleClick, this);
1326 this.el.on('click', this.onClick, this);
1331 onToggleClick : function()
1333 var headerEl = this.headerEl();
1349 if(this.fireEvent('expand', this)) {
1351 this.expanded = true;
1353 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1355 this.el.select('.panel-body',true).first().removeClass('hide');
1357 var toggleEl = this.toggleEl();
1363 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1368 collapse : function()
1370 if(this.fireEvent('collapse', this)) {
1372 this.expanded = false;
1374 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1375 this.el.select('.panel-body',true).first().addClass('hide');
1377 var toggleEl = this.toggleEl();
1383 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1387 toggleEl : function()
1389 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1393 return this.el.select('.panel-heading .fa',true).first();
1396 headerEl : function()
1398 if(!this.el || !this.panel.length || !this.header.length){
1402 return this.el.select('.panel-heading',true).first()
1407 if(!this.el || !this.panel.length){
1411 return this.el.select('.panel-body',true).first()
1414 titleEl : function()
1416 if(!this.el || !this.panel.length || !this.header.length){
1420 return this.el.select('.panel-title',true).first();
1423 setTitle : function(v)
1425 var titleEl = this.titleEl();
1431 titleEl.dom.innerHTML = v;
1434 getTitle : function()
1437 var titleEl = this.titleEl();
1443 return titleEl.dom.innerHTML;
1446 setRightTitle : function(v)
1448 var t = this.el.select('.panel-header-right',true).first();
1454 t.dom.innerHTML = v;
1457 onClick : function(e)
1461 this.fireEvent('click', this, e);
1474 * @class Roo.bootstrap.Img
1475 * @extends Roo.bootstrap.Component
1476 * Bootstrap Img class
1477 * @cfg {Boolean} imgResponsive false | true
1478 * @cfg {String} border rounded | circle | thumbnail
1479 * @cfg {String} src image source
1480 * @cfg {String} alt image alternative text
1481 * @cfg {String} href a tag href
1482 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1483 * @cfg {String} xsUrl xs image source
1484 * @cfg {String} smUrl sm image source
1485 * @cfg {String} mdUrl md image source
1486 * @cfg {String} lgUrl lg image source
1489 * Create a new Input
1490 * @param {Object} config The config object
1493 Roo.bootstrap.Img = function(config){
1494 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1500 * The img click event for the img.
1501 * @param {Roo.EventObject} e
1507 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1509 imgResponsive: true,
1519 getAutoCreate : function()
1521 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1522 return this.createSingleImg();
1527 cls: 'roo-image-responsive-group',
1532 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1534 if(!_this[size + 'Url']){
1540 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1541 html: _this.html || cfg.html,
1542 src: _this[size + 'Url']
1545 img.cls += ' roo-image-responsive-' + size;
1547 var s = ['xs', 'sm', 'md', 'lg'];
1549 s.splice(s.indexOf(size), 1);
1551 Roo.each(s, function(ss){
1552 img.cls += ' hidden-' + ss;
1555 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1556 cfg.cls += ' img-' + _this.border;
1560 cfg.alt = _this.alt;
1573 a.target = _this.target;
1577 cfg.cn.push((_this.href) ? a : img);
1584 createSingleImg : function()
1588 cls: (this.imgResponsive) ? 'img-responsive' : '',
1590 src : 'about:blank' // just incase src get's set to undefined?!?
1593 cfg.html = this.html || cfg.html;
1595 cfg.src = this.src || cfg.src;
1597 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1598 cfg.cls += ' img-' + this.border;
1615 a.target = this.target;
1620 return (this.href) ? a : cfg;
1623 initEvents: function()
1626 this.el.on('click', this.onClick, this);
1631 onClick : function(e)
1633 Roo.log('img onclick');
1634 this.fireEvent('click', this, e);
1637 * Sets the url of the image - used to update it
1638 * @param {String} url the url of the image
1641 setSrc : function(url)
1645 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1646 this.el.dom.src = url;
1650 this.el.select('img', true).first().dom.src = url;
1666 * @class Roo.bootstrap.Link
1667 * @extends Roo.bootstrap.Component
1668 * Bootstrap Link Class
1669 * @cfg {String} alt image alternative text
1670 * @cfg {String} href a tag href
1671 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1672 * @cfg {String} html the content of the link.
1673 * @cfg {String} anchor name for the anchor link
1674 * @cfg {String} fa - favicon
1676 * @cfg {Boolean} preventDefault (true | false) default false
1680 * Create a new Input
1681 * @param {Object} config The config object
1684 Roo.bootstrap.Link = function(config){
1685 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1691 * The img click event for the img.
1692 * @param {Roo.EventObject} e
1698 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1702 preventDefault: false,
1708 getAutoCreate : function()
1710 var html = this.html || '';
1712 if (this.fa !== false) {
1713 html = '<i class="fa fa-' + this.fa + '"></i>';
1718 // anchor's do not require html/href...
1719 if (this.anchor === false) {
1721 cfg.href = this.href || '#';
1723 cfg.name = this.anchor;
1724 if (this.html !== false || this.fa !== false) {
1727 if (this.href !== false) {
1728 cfg.href = this.href;
1732 if(this.alt !== false){
1737 if(this.target !== false) {
1738 cfg.target = this.target;
1744 initEvents: function() {
1746 if(!this.href || this.preventDefault){
1747 this.el.on('click', this.onClick, this);
1751 onClick : function(e)
1753 if(this.preventDefault){
1756 //Roo.log('img onclick');
1757 this.fireEvent('click', this, e);
1770 * @class Roo.bootstrap.Header
1771 * @extends Roo.bootstrap.Component
1772 * Bootstrap Header class
1773 * @cfg {String} html content of header
1774 * @cfg {Number} level (1|2|3|4|5|6) default 1
1777 * Create a new Header
1778 * @param {Object} config The config object
1782 Roo.bootstrap.Header = function(config){
1783 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1786 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1794 getAutoCreate : function(){
1799 tag: 'h' + (1 *this.level),
1800 html: this.html || ''
1812 * Ext JS Library 1.1.1
1813 * Copyright(c) 2006-2007, Ext JS, LLC.
1815 * Originally Released Under LGPL - original licence link has changed is not relivant.
1818 * <script type="text/javascript">
1822 * @class Roo.bootstrap.MenuMgr
1823 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1826 Roo.bootstrap.MenuMgr = function(){
1827 var menus, active, groups = {}, attached = false, lastShow = new Date();
1829 // private - called when first menu is created
1832 active = new Roo.util.MixedCollection();
1833 Roo.get(document).addKeyListener(27, function(){
1834 if(active.length > 0){
1842 if(active && active.length > 0){
1843 var c = active.clone();
1853 if(active.length < 1){
1854 Roo.get(document).un("mouseup", onMouseDown);
1862 var last = active.last();
1863 lastShow = new Date();
1866 Roo.get(document).on("mouseup", onMouseDown);
1871 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1872 m.parentMenu.activeChild = m;
1873 }else if(last && last.isVisible()){
1874 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1879 function onBeforeHide(m){
1881 m.activeChild.hide();
1883 if(m.autoHideTimer){
1884 clearTimeout(m.autoHideTimer);
1885 delete m.autoHideTimer;
1890 function onBeforeShow(m){
1891 var pm = m.parentMenu;
1892 if(!pm && !m.allowOtherMenus){
1894 }else if(pm && pm.activeChild && active != m){
1895 pm.activeChild.hide();
1899 // private this should really trigger on mouseup..
1900 function onMouseDown(e){
1901 Roo.log("on Mouse Up");
1903 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1904 Roo.log("MenuManager hideAll");
1913 function onBeforeCheck(mi, state){
1915 var g = groups[mi.group];
1916 for(var i = 0, l = g.length; i < l; i++){
1918 g[i].setChecked(false);
1927 * Hides all menus that are currently visible
1929 hideAll : function(){
1934 register : function(menu){
1938 menus[menu.id] = menu;
1939 menu.on("beforehide", onBeforeHide);
1940 menu.on("hide", onHide);
1941 menu.on("beforeshow", onBeforeShow);
1942 menu.on("show", onShow);
1944 if(g && menu.events["checkchange"]){
1948 groups[g].push(menu);
1949 menu.on("checkchange", onCheck);
1954 * Returns a {@link Roo.menu.Menu} object
1955 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1956 * be used to generate and return a new Menu instance.
1958 get : function(menu){
1959 if(typeof menu == "string"){ // menu id
1961 }else if(menu.events){ // menu instance
1964 /*else if(typeof menu.length == 'number'){ // array of menu items?
1965 return new Roo.bootstrap.Menu({items:menu});
1966 }else{ // otherwise, must be a config
1967 return new Roo.bootstrap.Menu(menu);
1974 unregister : function(menu){
1975 delete menus[menu.id];
1976 menu.un("beforehide", onBeforeHide);
1977 menu.un("hide", onHide);
1978 menu.un("beforeshow", onBeforeShow);
1979 menu.un("show", onShow);
1981 if(g && menu.events["checkchange"]){
1982 groups[g].remove(menu);
1983 menu.un("checkchange", onCheck);
1988 registerCheckable : function(menuItem){
1989 var g = menuItem.group;
1994 groups[g].push(menuItem);
1995 menuItem.on("beforecheckchange", onBeforeCheck);
2000 unregisterCheckable : function(menuItem){
2001 var g = menuItem.group;
2003 groups[g].remove(menuItem);
2004 menuItem.un("beforecheckchange", onBeforeCheck);
2016 * @class Roo.bootstrap.Menu
2017 * @extends Roo.bootstrap.Component
2018 * Bootstrap Menu class - container for MenuItems
2019 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2020 * @cfg {bool} hidden if the menu should be hidden when rendered.
2021 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2022 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2026 * @param {Object} config The config object
2030 Roo.bootstrap.Menu = function(config){
2031 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2032 if (this.registerMenu && this.type != 'treeview') {
2033 Roo.bootstrap.MenuMgr.register(this);
2040 * Fires before this menu is displayed
2041 * @param {Roo.menu.Menu} this
2046 * Fires before this menu is hidden
2047 * @param {Roo.menu.Menu} this
2052 * Fires after this menu is displayed
2053 * @param {Roo.menu.Menu} this
2058 * Fires after this menu is hidden
2059 * @param {Roo.menu.Menu} this
2064 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2065 * @param {Roo.menu.Menu} this
2066 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2067 * @param {Roo.EventObject} e
2072 * Fires when the mouse is hovering over this menu
2073 * @param {Roo.menu.Menu} this
2074 * @param {Roo.EventObject} e
2075 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2080 * Fires when the mouse exits this menu
2081 * @param {Roo.menu.Menu} this
2082 * @param {Roo.EventObject} e
2083 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2088 * Fires when a menu item contained in this menu is clicked
2089 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2090 * @param {Roo.EventObject} e
2094 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2097 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2101 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2104 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2106 registerMenu : true,
2108 menuItems :false, // stores the menu items..
2118 getChildContainer : function() {
2122 getAutoCreate : function(){
2124 //if (['right'].indexOf(this.align)!==-1) {
2125 // cfg.cn[1].cls += ' pull-right'
2131 cls : 'dropdown-menu' ,
2132 style : 'z-index:1000'
2136 if (this.type === 'submenu') {
2137 cfg.cls = 'submenu active';
2139 if (this.type === 'treeview') {
2140 cfg.cls = 'treeview-menu';
2145 initEvents : function() {
2147 // Roo.log("ADD event");
2148 // Roo.log(this.triggerEl.dom);
2150 this.triggerEl.on('click', this.onTriggerClick, this);
2152 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2155 if (this.triggerEl.hasClass('nav-item')) {
2156 // dropdown toggle on the 'a' in BS4?
2157 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2159 this.triggerEl.addClass('dropdown-toggle');
2162 this.el.on('touchstart' , this.onTouch, this);
2164 this.el.on('click' , this.onClick, this);
2166 this.el.on("mouseover", this.onMouseOver, this);
2167 this.el.on("mouseout", this.onMouseOut, this);
2171 findTargetItem : function(e)
2173 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2177 //Roo.log(t); Roo.log(t.id);
2179 //Roo.log(this.menuitems);
2180 return this.menuitems.get(t.id);
2182 //return this.items.get(t.menuItemId);
2188 onTouch : function(e)
2190 Roo.log("menu.onTouch");
2191 //e.stopEvent(); this make the user popdown broken
2195 onClick : function(e)
2197 Roo.log("menu.onClick");
2199 var t = this.findTargetItem(e);
2200 if(!t || t.isContainer){
2205 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2206 if(t == this.activeItem && t.shouldDeactivate(e)){
2207 this.activeItem.deactivate();
2208 delete this.activeItem;
2212 this.setActiveItem(t, true);
2220 Roo.log('pass click event');
2224 this.fireEvent("click", this, t, e);
2228 if(!t.href.length || t.href == '#'){
2229 (function() { _this.hide(); }).defer(100);
2234 onMouseOver : function(e){
2235 var t = this.findTargetItem(e);
2238 // if(t.canActivate && !t.disabled){
2239 // this.setActiveItem(t, true);
2243 this.fireEvent("mouseover", this, e, t);
2245 isVisible : function(){
2246 return !this.hidden;
2248 onMouseOut : function(e){
2249 var t = this.findTargetItem(e);
2252 // if(t == this.activeItem && t.shouldDeactivate(e)){
2253 // this.activeItem.deactivate();
2254 // delete this.activeItem;
2257 this.fireEvent("mouseout", this, e, t);
2262 * Displays this menu relative to another element
2263 * @param {String/HTMLElement/Roo.Element} element The element to align to
2264 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2265 * the element (defaults to this.defaultAlign)
2266 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2268 show : function(el, pos, parentMenu){
2269 this.parentMenu = parentMenu;
2273 this.fireEvent("beforeshow", this);
2274 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2277 * Displays this menu at a specific xy position
2278 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2279 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2281 showAt : function(xy, parentMenu, /* private: */_e){
2282 this.parentMenu = parentMenu;
2287 this.fireEvent("beforeshow", this);
2288 //xy = this.el.adjustForConstraints(xy);
2292 this.hideMenuItems();
2293 this.hidden = false;
2294 this.triggerEl.addClass('open');
2295 this.el.addClass('show');
2297 // reassign x when hitting right
2298 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2299 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2302 // reassign y when hitting bottom
2303 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2304 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2307 // but the list may align on trigger left or trigger top... should it be a properity?
2309 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2314 this.fireEvent("show", this);
2320 this.doFocus.defer(50, this);
2324 doFocus : function(){
2326 this.focusEl.focus();
2331 * Hides this menu and optionally all parent menus
2332 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2334 hide : function(deep)
2337 this.hideMenuItems();
2338 if(this.el && this.isVisible()){
2339 this.fireEvent("beforehide", this);
2340 if(this.activeItem){
2341 this.activeItem.deactivate();
2342 this.activeItem = null;
2344 this.triggerEl.removeClass('open');;
2345 this.el.removeClass('show');
2347 this.fireEvent("hide", this);
2349 if(deep === true && this.parentMenu){
2350 this.parentMenu.hide(true);
2354 onTriggerClick : function(e)
2356 Roo.log('trigger click');
2358 var target = e.getTarget();
2360 Roo.log(target.nodeName.toLowerCase());
2362 if(target.nodeName.toLowerCase() === 'i'){
2368 onTriggerPress : function(e)
2370 Roo.log('trigger press');
2371 //Roo.log(e.getTarget());
2372 // Roo.log(this.triggerEl.dom);
2374 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2375 var pel = Roo.get(e.getTarget());
2376 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2377 Roo.log('is treeview or dropdown?');
2381 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2385 if (this.isVisible()) {
2390 this.show(this.triggerEl, false, false);
2393 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2400 hideMenuItems : function()
2402 Roo.log("hide Menu Items");
2406 //$(backdrop).remove()
2407 this.el.select('.open',true).each(function(aa) {
2409 aa.removeClass('open');
2410 //var parent = getParent($(this))
2411 //var relatedTarget = { relatedTarget: this }
2413 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2414 //if (e.isDefaultPrevented()) return
2415 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2418 addxtypeChild : function (tree, cntr) {
2419 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2421 this.menuitems.add(comp);
2433 this.getEl().dom.innerHTML = '';
2434 this.menuitems.clear();
2448 * @class Roo.bootstrap.MenuItem
2449 * @extends Roo.bootstrap.Component
2450 * Bootstrap MenuItem class
2451 * @cfg {String} html the menu label
2452 * @cfg {String} href the link
2453 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2454 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2455 * @cfg {Boolean} active used on sidebars to highlight active itesm
2456 * @cfg {String} fa favicon to show on left of menu item.
2457 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2461 * Create a new MenuItem
2462 * @param {Object} config The config object
2466 Roo.bootstrap.MenuItem = function(config){
2467 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2472 * The raw click event for the entire grid.
2473 * @param {Roo.bootstrap.MenuItem} this
2474 * @param {Roo.EventObject} e
2480 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2484 preventDefault: false,
2485 isContainer : false,
2489 getAutoCreate : function(){
2491 if(this.isContainer){
2494 cls: 'dropdown-menu-item dropdown-item'
2508 if (this.fa !== false) {
2511 cls : 'fa fa-' + this.fa
2520 cls: 'dropdown-menu-item dropdown-item',
2523 if (this.parent().type == 'treeview') {
2524 cfg.cls = 'treeview-menu';
2527 cfg.cls += ' active';
2532 anc.href = this.href || cfg.cn[0].href ;
2533 ctag.html = this.html || cfg.cn[0].html ;
2537 initEvents: function()
2539 if (this.parent().type == 'treeview') {
2540 this.el.select('a').on('click', this.onClick, this);
2544 this.menu.parentType = this.xtype;
2545 this.menu.triggerEl = this.el;
2546 this.menu = this.addxtype(Roo.apply({}, this.menu));
2550 onClick : function(e)
2552 Roo.log('item on click ');
2554 if(this.preventDefault){
2557 //this.parent().hideMenuItems();
2559 this.fireEvent('click', this, e);
2578 * @class Roo.bootstrap.MenuSeparator
2579 * @extends Roo.bootstrap.Component
2580 * Bootstrap MenuSeparator class
2583 * Create a new MenuItem
2584 * @param {Object} config The config object
2588 Roo.bootstrap.MenuSeparator = function(config){
2589 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2592 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2594 getAutoCreate : function(){
2613 * @class Roo.bootstrap.Modal
2614 * @extends Roo.bootstrap.Component
2615 * Bootstrap Modal class
2616 * @cfg {String} title Title of dialog
2617 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2618 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2619 * @cfg {Boolean} specificTitle default false
2620 * @cfg {Array} buttons Array of buttons or standard button set..
2621 * @cfg {String} buttonPosition (left|right|center) default right
2622 * @cfg {Boolean} animate default true
2623 * @cfg {Boolean} allow_close default true
2624 * @cfg {Boolean} fitwindow default false
2625 * @cfg {String} size (sm|lg) default empty
2626 * @cfg {Number} max_width set the max width of modal
2630 * Create a new Modal Dialog
2631 * @param {Object} config The config object
2634 Roo.bootstrap.Modal = function(config){
2635 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2640 * The raw btnclick event for the button
2641 * @param {Roo.EventObject} e
2646 * Fire when dialog resize
2647 * @param {Roo.bootstrap.Modal} this
2648 * @param {Roo.EventObject} e
2652 this.buttons = this.buttons || [];
2655 this.tmpl = Roo.factory(this.tmpl);
2660 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2662 title : 'test dialog',
2672 specificTitle: false,
2674 buttonPosition: 'right',
2697 onRender : function(ct, position)
2699 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2702 var cfg = Roo.apply({}, this.getAutoCreate());
2705 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2707 //if (!cfg.name.length) {
2711 cfg.cls += ' ' + this.cls;
2714 cfg.style = this.style;
2716 this.el = Roo.get(document.body).createChild(cfg, position);
2718 //var type = this.el.dom.type;
2721 if(this.tabIndex !== undefined){
2722 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2725 this.dialogEl = this.el.select('.modal-dialog',true).first();
2726 this.bodyEl = this.el.select('.modal-body',true).first();
2727 this.closeEl = this.el.select('.modal-header .close', true).first();
2728 this.headerEl = this.el.select('.modal-header',true).first();
2729 this.titleEl = this.el.select('.modal-title',true).first();
2730 this.footerEl = this.el.select('.modal-footer',true).first();
2732 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2734 //this.el.addClass("x-dlg-modal");
2736 if (this.buttons.length) {
2737 Roo.each(this.buttons, function(bb) {
2738 var b = Roo.apply({}, bb);
2739 b.xns = b.xns || Roo.bootstrap;
2740 b.xtype = b.xtype || 'Button';
2741 if (typeof(b.listeners) == 'undefined') {
2742 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2745 var btn = Roo.factory(b);
2747 btn.render(this.el.select('.modal-footer div').first());
2751 // render the children.
2754 if(typeof(this.items) != 'undefined'){
2755 var items = this.items;
2758 for(var i =0;i < items.length;i++) {
2759 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2763 this.items = nitems;
2765 // where are these used - they used to be body/close/footer
2769 //this.el.addClass([this.fieldClass, this.cls]);
2773 getAutoCreate : function()
2777 html : this.html || ''
2782 cls : 'modal-title',
2786 if(this.specificTitle){
2792 if (this.allow_close && Roo.bootstrap.version == 3) {
2802 if (this.allow_close && Roo.bootstrap.version == 4) {
2812 if(this.size.length){
2813 size = 'modal-' + this.size;
2820 cls: "modal-dialog " + size,
2823 cls : "modal-content",
2826 cls : 'modal-header',
2831 cls : 'modal-footer',
2835 cls: 'btn-' + this.buttonPosition
2852 modal.cls += ' fade';
2858 getChildContainer : function() {
2863 getButtonContainer : function() {
2864 return this.el.select('.modal-footer div',true).first();
2867 initEvents : function()
2869 if (this.allow_close) {
2870 this.closeEl.on('click', this.hide, this);
2872 Roo.EventManager.onWindowResize(this.resize, this, true);
2879 this.maskEl.setSize(
2880 Roo.lib.Dom.getViewWidth(true),
2881 Roo.lib.Dom.getViewHeight(true)
2884 if (this.fitwindow) {
2886 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2887 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2892 if(this.max_width !== 0) {
2894 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2897 this.setSize(w, this.height);
2901 if(this.max_height) {
2902 this.setSize(w,Math.min(
2904 Roo.lib.Dom.getViewportHeight(true) - 60
2910 if(!this.fit_content) {
2911 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2915 this.setSize(w, Math.min(
2917 this.headerEl.getHeight() +
2918 this.footerEl.getHeight() +
2919 this.getChildHeight(this.bodyEl.dom.childNodes),
2920 Roo.lib.Dom.getViewportHeight(true) - 60)
2926 setSize : function(w,h)
2937 if (!this.rendered) {
2941 //this.el.setStyle('display', 'block');
2942 this.el.removeClass('hideing');
2943 this.el.dom.style.display='block';
2945 Roo.get(document.body).addClass('modal-open');
2947 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2950 this.el.addClass('show');
2951 this.el.addClass('in');
2954 this.el.addClass('show');
2955 this.el.addClass('in');
2958 // not sure how we can show data in here..
2960 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2963 Roo.get(document.body).addClass("x-body-masked");
2965 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2966 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2967 this.maskEl.dom.style.display = 'block';
2968 this.maskEl.addClass('show');
2973 this.fireEvent('show', this);
2975 // set zindex here - otherwise it appears to be ignored...
2976 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2979 this.items.forEach( function(e) {
2980 e.layout ? e.layout() : false;
2988 if(this.fireEvent("beforehide", this) !== false){
2990 this.maskEl.removeClass('show');
2992 this.maskEl.dom.style.display = '';
2993 Roo.get(document.body).removeClass("x-body-masked");
2994 this.el.removeClass('in');
2995 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2997 if(this.animate){ // why
2998 this.el.addClass('hideing');
2999 this.el.removeClass('show');
3001 if (!this.el.hasClass('hideing')) {
3002 return; // it's been shown again...
3005 this.el.dom.style.display='';
3007 Roo.get(document.body).removeClass('modal-open');
3008 this.el.removeClass('hideing');
3012 this.el.removeClass('show');
3013 this.el.dom.style.display='';
3014 Roo.get(document.body).removeClass('modal-open');
3017 this.fireEvent('hide', this);
3020 isVisible : function()
3023 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3027 addButton : function(str, cb)
3031 var b = Roo.apply({}, { html : str } );
3032 b.xns = b.xns || Roo.bootstrap;
3033 b.xtype = b.xtype || 'Button';
3034 if (typeof(b.listeners) == 'undefined') {
3035 b.listeners = { click : cb.createDelegate(this) };
3038 var btn = Roo.factory(b);
3040 btn.render(this.el.select('.modal-footer div').first());
3046 setDefaultButton : function(btn)
3048 //this.el.select('.modal-footer').()
3052 resizeTo: function(w,h)
3056 this.dialogEl.setWidth(w);
3057 if (this.diff === false) {
3058 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3061 this.bodyEl.setHeight(h - this.diff);
3063 this.fireEvent('resize', this);
3066 setContentSize : function(w, h)
3070 onButtonClick: function(btn,e)
3073 this.fireEvent('btnclick', btn.name, e);
3076 * Set the title of the Dialog
3077 * @param {String} str new Title
3079 setTitle: function(str) {
3080 this.titleEl.dom.innerHTML = str;
3083 * Set the body of the Dialog
3084 * @param {String} str new Title
3086 setBody: function(str) {
3087 this.bodyEl.dom.innerHTML = str;
3090 * Set the body of the Dialog using the template
3091 * @param {Obj} data - apply this data to the template and replace the body contents.
3093 applyBody: function(obj)
3096 Roo.log("Error - using apply Body without a template");
3099 this.tmpl.overwrite(this.bodyEl, obj);
3102 getChildHeight : function(child_nodes)
3106 child_nodes.length == 0
3111 var child_height = 0;
3113 for(var i = 0; i < child_nodes.length; i++) {
3116 * for modal with tabs...
3117 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3119 var layout_childs = child_nodes[i].childNodes;
3121 for(var j = 0; j < layout_childs.length; j++) {
3123 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3125 var layout_body_childs = layout_childs[j].childNodes;
3127 for(var k = 0; k < layout_body_childs.length; k++) {
3129 if(layout_body_childs[k].classList.contains('navbar')) {
3130 child_height += layout_body_childs[k].offsetHeight;
3134 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3136 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3138 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3140 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3141 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3156 child_height += child_nodes[i].offsetHeight;
3157 // Roo.log(child_nodes[i].offsetHeight);
3160 return child_height;
3166 Roo.apply(Roo.bootstrap.Modal, {
3168 * Button config that displays a single OK button
3177 * Button config that displays Yes and No buttons
3193 * Button config that displays OK and Cancel buttons
3208 * Button config that displays Yes, No and Cancel buttons
3232 * messagebox - can be used as a replace
3236 * @class Roo.MessageBox
3237 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3241 Roo.Msg.alert('Status', 'Changes saved successfully.');
3243 // Prompt for user data:
3244 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3246 // process text value...
3250 // Show a dialog using config options:
3252 title:'Save Changes?',
3253 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3254 buttons: Roo.Msg.YESNOCANCEL,
3261 Roo.bootstrap.MessageBox = function(){
3262 var dlg, opt, mask, waitTimer;
3263 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3264 var buttons, activeTextEl, bwidth;
3268 var handleButton = function(button){
3270 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3274 var handleHide = function(){
3276 dlg.el.removeClass(opt.cls);
3279 // Roo.TaskMgr.stop(waitTimer);
3280 // waitTimer = null;
3285 var updateButtons = function(b){
3288 buttons["ok"].hide();
3289 buttons["cancel"].hide();
3290 buttons["yes"].hide();
3291 buttons["no"].hide();
3292 //dlg.footer.dom.style.display = 'none';
3295 dlg.footerEl.dom.style.display = '';
3296 for(var k in buttons){
3297 if(typeof buttons[k] != "function"){
3300 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3301 width += buttons[k].el.getWidth()+15;
3311 var handleEsc = function(d, k, e){
3312 if(opt && opt.closable !== false){
3322 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3323 * @return {Roo.BasicDialog} The BasicDialog element
3325 getDialog : function(){
3327 dlg = new Roo.bootstrap.Modal( {
3330 //constraintoviewport:false,
3332 //collapsible : false,
3337 //buttonAlign:"center",
3338 closeClick : function(){
3339 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3342 handleButton("cancel");
3347 dlg.on("hide", handleHide);
3349 //dlg.addKeyListener(27, handleEsc);
3351 this.buttons = buttons;
3352 var bt = this.buttonText;
3353 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3354 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3355 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3356 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3358 bodyEl = dlg.bodyEl.createChild({
3360 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3361 '<textarea class="roo-mb-textarea"></textarea>' +
3362 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3364 msgEl = bodyEl.dom.firstChild;
3365 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3366 textboxEl.enableDisplayMode();
3367 textboxEl.addKeyListener([10,13], function(){
3368 if(dlg.isVisible() && opt && opt.buttons){
3371 }else if(opt.buttons.yes){
3372 handleButton("yes");
3376 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3377 textareaEl.enableDisplayMode();
3378 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3379 progressEl.enableDisplayMode();
3381 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3382 var pf = progressEl.dom.firstChild;
3384 pp = Roo.get(pf.firstChild);
3385 pp.setHeight(pf.offsetHeight);
3393 * Updates the message box body text
3394 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3395 * the XHTML-compliant non-breaking space character '&#160;')
3396 * @return {Roo.MessageBox} This message box
3398 updateText : function(text)
3400 if(!dlg.isVisible() && !opt.width){
3401 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3402 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3404 msgEl.innerHTML = text || ' ';
3406 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3407 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3409 Math.min(opt.width || cw , this.maxWidth),
3410 Math.max(opt.minWidth || this.minWidth, bwidth)
3413 activeTextEl.setWidth(w);
3415 if(dlg.isVisible()){
3416 dlg.fixedcenter = false;
3418 // to big, make it scroll. = But as usual stupid IE does not support
3421 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3422 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3423 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3425 bodyEl.dom.style.height = '';
3426 bodyEl.dom.style.overflowY = '';
3429 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3431 bodyEl.dom.style.overflowX = '';
3434 dlg.setContentSize(w, bodyEl.getHeight());
3435 if(dlg.isVisible()){
3436 dlg.fixedcenter = true;
3442 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3443 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3444 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3445 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3446 * @return {Roo.MessageBox} This message box
3448 updateProgress : function(value, text){
3450 this.updateText(text);
3453 if (pp) { // weird bug on my firefox - for some reason this is not defined
3454 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3455 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3461 * Returns true if the message box is currently displayed
3462 * @return {Boolean} True if the message box is visible, else false
3464 isVisible : function(){
3465 return dlg && dlg.isVisible();
3469 * Hides the message box if it is displayed
3472 if(this.isVisible()){
3478 * Displays a new message box, or reinitializes an existing message box, based on the config options
3479 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3480 * The following config object properties are supported:
3482 Property Type Description
3483 ---------- --------------- ------------------------------------------------------------------------------------
3484 animEl String/Element An id or Element from which the message box should animate as it opens and
3485 closes (defaults to undefined)
3486 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3487 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3488 closable Boolean False to hide the top-right close button (defaults to true). Note that
3489 progress and wait dialogs will ignore this property and always hide the
3490 close button as they can only be closed programmatically.
3491 cls String A custom CSS class to apply to the message box element
3492 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3493 displayed (defaults to 75)
3494 fn Function A callback function to execute after closing the dialog. The arguments to the
3495 function will be btn (the name of the button that was clicked, if applicable,
3496 e.g. "ok"), and text (the value of the active text field, if applicable).
3497 Progress and wait dialogs will ignore this option since they do not respond to
3498 user actions and can only be closed programmatically, so any required function
3499 should be called by the same code after it closes the dialog.
3500 icon String A CSS class that provides a background image to be used as an icon for
3501 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3502 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3503 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3504 modal Boolean False to allow user interaction with the page while the message box is
3505 displayed (defaults to true)
3506 msg String A string that will replace the existing message box body text (defaults
3507 to the XHTML-compliant non-breaking space character ' ')
3508 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3509 progress Boolean True to display a progress bar (defaults to false)
3510 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3511 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3512 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3513 title String The title text
3514 value String The string value to set into the active textbox element if displayed
3515 wait Boolean True to display a progress bar (defaults to false)
3516 width Number The width of the dialog in pixels
3523 msg: 'Please enter your address:',
3525 buttons: Roo.MessageBox.OKCANCEL,
3528 animEl: 'addAddressBtn'
3531 * @param {Object} config Configuration options
3532 * @return {Roo.MessageBox} This message box
3534 show : function(options)
3537 // this causes nightmares if you show one dialog after another
3538 // especially on callbacks..
3540 if(this.isVisible()){
3543 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3544 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3545 Roo.log("New Dialog Message:" + options.msg )
3546 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3547 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3550 var d = this.getDialog();
3552 d.setTitle(opt.title || " ");
3553 d.closeEl.setDisplayed(opt.closable !== false);
3554 activeTextEl = textboxEl;
3555 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3560 textareaEl.setHeight(typeof opt.multiline == "number" ?
3561 opt.multiline : this.defaultTextHeight);
3562 activeTextEl = textareaEl;
3571 progressEl.setDisplayed(opt.progress === true);
3572 this.updateProgress(0);
3573 activeTextEl.dom.value = opt.value || "";
3575 dlg.setDefaultButton(activeTextEl);
3577 var bs = opt.buttons;
3581 }else if(bs && bs.yes){
3582 db = buttons["yes"];
3584 dlg.setDefaultButton(db);
3586 bwidth = updateButtons(opt.buttons);
3587 this.updateText(opt.msg);
3589 d.el.addClass(opt.cls);
3591 d.proxyDrag = opt.proxyDrag === true;
3592 d.modal = opt.modal !== false;
3593 d.mask = opt.modal !== false ? mask : false;
3595 // force it to the end of the z-index stack so it gets a cursor in FF
3596 document.body.appendChild(dlg.el.dom);
3597 d.animateTarget = null;
3598 d.show(options.animEl);
3604 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3605 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3606 * and closing the message box when the process is complete.
3607 * @param {String} title The title bar text
3608 * @param {String} msg The message box body text
3609 * @return {Roo.MessageBox} This message box
3611 progress : function(title, msg){
3618 minWidth: this.minProgressWidth,
3625 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3626 * If a callback function is passed it will be called after the user clicks the button, and the
3627 * id of the button that was clicked will be passed as the only parameter to the callback
3628 * (could also be the top-right close button).
3629 * @param {String} title The title bar text
3630 * @param {String} msg The message box body text
3631 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3632 * @param {Object} scope (optional) The scope of the callback function
3633 * @return {Roo.MessageBox} This message box
3635 alert : function(title, msg, fn, scope)
3650 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3651 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3652 * You are responsible for closing the message box when the process is complete.
3653 * @param {String} msg The message box body text
3654 * @param {String} title (optional) The title bar text
3655 * @return {Roo.MessageBox} This message box
3657 wait : function(msg, title){
3668 waitTimer = Roo.TaskMgr.start({
3670 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3678 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3679 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3680 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3681 * @param {String} title The title bar text
3682 * @param {String} msg The message box body text
3683 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3684 * @param {Object} scope (optional) The scope of the callback function
3685 * @return {Roo.MessageBox} This message box
3687 confirm : function(title, msg, fn, scope){
3691 buttons: this.YESNO,
3700 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3701 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3702 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3703 * (could also be the top-right close button) and the text that was entered will be passed as the two
3704 * parameters to the callback.
3705 * @param {String} title The title bar text
3706 * @param {String} msg The message box body text
3707 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3708 * @param {Object} scope (optional) The scope of the callback function
3709 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3710 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3711 * @return {Roo.MessageBox} This message box
3713 prompt : function(title, msg, fn, scope, multiline){
3717 buttons: this.OKCANCEL,
3722 multiline: multiline,
3729 * Button config that displays a single OK button
3734 * Button config that displays Yes and No buttons
3737 YESNO : {yes:true, no:true},
3739 * Button config that displays OK and Cancel buttons
3742 OKCANCEL : {ok:true, cancel:true},
3744 * Button config that displays Yes, No and Cancel buttons
3747 YESNOCANCEL : {yes:true, no:true, cancel:true},
3750 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3753 defaultTextHeight : 75,
3755 * The maximum width in pixels of the message box (defaults to 600)
3760 * The minimum width in pixels of the message box (defaults to 100)
3765 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3766 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3769 minProgressWidth : 250,
3771 * An object containing the default button text strings that can be overriden for localized language support.
3772 * Supported properties are: ok, cancel, yes and no.
3773 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3786 * Shorthand for {@link Roo.MessageBox}
3788 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3789 Roo.Msg = Roo.Msg || Roo.MessageBox;
3798 * @class Roo.bootstrap.Navbar
3799 * @extends Roo.bootstrap.Component
3800 * Bootstrap Navbar class
3803 * Create a new Navbar
3804 * @param {Object} config The config object
3808 Roo.bootstrap.Navbar = function(config){
3809 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3813 * @event beforetoggle
3814 * Fire before toggle the menu
3815 * @param {Roo.EventObject} e
3817 "beforetoggle" : true
3821 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3830 getAutoCreate : function(){
3833 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3837 initEvents :function ()
3839 //Roo.log(this.el.select('.navbar-toggle',true));
3840 this.el.select('.navbar-toggle',true).on('click', function() {
3841 if(this.fireEvent('beforetoggle', this) !== false){
3842 this.el.select('.navbar-collapse',true).toggleClass('in');
3852 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3854 var size = this.el.getSize();
3855 this.maskEl.setSize(size.width, size.height);
3856 this.maskEl.enableDisplayMode("block");
3865 getChildContainer : function()
3867 if (this.el.select('.collapse').getCount()) {
3868 return this.el.select('.collapse',true).first();
3901 * @class Roo.bootstrap.NavSimplebar
3902 * @extends Roo.bootstrap.Navbar
3903 * Bootstrap Sidebar class
3905 * @cfg {Boolean} inverse is inverted color
3907 * @cfg {String} type (nav | pills | tabs)
3908 * @cfg {Boolean} arrangement stacked | justified
3909 * @cfg {String} align (left | right) alignment
3911 * @cfg {Boolean} main (true|false) main nav bar? default false
3912 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3914 * @cfg {String} tag (header|footer|nav|div) default is nav
3916 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3920 * Create a new Sidebar
3921 * @param {Object} config The config object
3925 Roo.bootstrap.NavSimplebar = function(config){
3926 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3929 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3945 getAutoCreate : function(){
3949 tag : this.tag || 'div',
3950 cls : 'navbar navbar-expand-lg'
3952 if (['light','white'].indexOf(this.weight) > -1) {
3953 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
3955 cfg.cls += ' bg-' + this.weight;
3967 this.type = this.type || 'nav';
3968 if (['tabs','pills'].indexOf(this.type)!==-1) {
3969 cfg.cn[0].cls += ' nav-' + this.type
3973 if (this.type!=='nav') {
3974 Roo.log('nav type must be nav/tabs/pills')
3976 cfg.cn[0].cls += ' navbar-nav'
3982 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3983 cfg.cn[0].cls += ' nav-' + this.arrangement;
3987 if (this.align === 'right') {
3988 cfg.cn[0].cls += ' navbar-right';
3992 cfg.cls += ' navbar-inverse';
4016 * navbar-expand-md fixed-top
4020 * @class Roo.bootstrap.NavHeaderbar
4021 * @extends Roo.bootstrap.NavSimplebar
4022 * Bootstrap Sidebar class
4024 * @cfg {String} brand what is brand
4025 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4026 * @cfg {String} brand_href href of the brand
4027 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4028 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4029 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4030 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4033 * Create a new Sidebar
4034 * @param {Object} config The config object
4038 Roo.bootstrap.NavHeaderbar = function(config){
4039 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4043 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4050 desktopCenter : false,
4053 getAutoCreate : function(){
4056 tag: this.nav || 'nav',
4057 cls: 'navbar navbar-expand-md',
4063 if (this.desktopCenter) {
4064 cn.push({cls : 'container', cn : []});
4071 cls: 'navbar-header',
4076 cls: 'navbar-toggle navbar-toggler',
4077 'data-toggle': 'collapse',
4082 html: 'Toggle navigation'
4086 cls: 'icon-bar navbar-toggler-icon'
4104 cls: 'collapse navbar-collapse',
4108 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4110 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4111 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4113 // tag can override this..
4115 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4118 if (this.brand !== '') {
4121 href: this.brand_href ? this.brand_href : '#',
4122 cls: 'navbar-brand',
4130 cfg.cls += ' main-nav';
4138 getHeaderChildContainer : function()
4140 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4141 return this.el.select('.navbar-header',true).first();
4144 return this.getChildContainer();
4148 initEvents : function()
4150 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4152 if (this.autohide) {
4157 Roo.get(document).on('scroll',function(e) {
4158 var ns = Roo.get(document).getScroll().top;
4159 var os = prevScroll;
4163 ft.removeClass('slideDown');
4164 ft.addClass('slideUp');
4167 ft.removeClass('slideUp');
4168 ft.addClass('slideDown');
4189 * @class Roo.bootstrap.NavSidebar
4190 * @extends Roo.bootstrap.Navbar
4191 * Bootstrap Sidebar class
4194 * Create a new Sidebar
4195 * @param {Object} config The config object
4199 Roo.bootstrap.NavSidebar = function(config){
4200 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4203 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4205 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4207 getAutoCreate : function(){
4212 cls: 'sidebar sidebar-nav'
4234 * @class Roo.bootstrap.NavGroup
4235 * @extends Roo.bootstrap.Component
4236 * Bootstrap NavGroup class
4237 * @cfg {String} align (left|right)
4238 * @cfg {Boolean} inverse
4239 * @cfg {String} type (nav|pills|tab) default nav
4240 * @cfg {String} navId - reference Id for navbar.
4244 * Create a new nav group
4245 * @param {Object} config The config object
4248 Roo.bootstrap.NavGroup = function(config){
4249 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4252 Roo.bootstrap.NavGroup.register(this);
4256 * Fires when the active item changes
4257 * @param {Roo.bootstrap.NavGroup} this
4258 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4259 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4266 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4277 getAutoCreate : function()
4279 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4286 if (['tabs','pills'].indexOf(this.type)!==-1) {
4287 cfg.cls += ' nav-' + this.type
4289 if (this.type!=='nav') {
4290 Roo.log('nav type must be nav/tabs/pills')
4292 cfg.cls += ' navbar-nav'
4295 if (this.parent() && this.parent().sidebar) {
4298 cls: 'dashboard-menu sidebar-menu'
4304 if (this.form === true) {
4310 if (this.align === 'right') {
4311 cfg.cls += ' navbar-right ml-md-auto';
4313 cfg.cls += ' navbar-left';
4317 if (this.align === 'right') {
4318 cfg.cls += ' navbar-right ml-md-auto';
4320 cfg.cls += ' mr-auto';
4324 cfg.cls += ' navbar-inverse';
4332 * sets the active Navigation item
4333 * @param {Roo.bootstrap.NavItem} the new current navitem
4335 setActiveItem : function(item)
4338 Roo.each(this.navItems, function(v){
4343 v.setActive(false, true);
4350 item.setActive(true, true);
4351 this.fireEvent('changed', this, item, prev);
4356 * gets the active Navigation item
4357 * @return {Roo.bootstrap.NavItem} the current navitem
4359 getActive : function()
4363 Roo.each(this.navItems, function(v){
4374 indexOfNav : function()
4378 Roo.each(this.navItems, function(v,i){
4389 * adds a Navigation item
4390 * @param {Roo.bootstrap.NavItem} the navitem to add
4392 addItem : function(cfg)
4394 var cn = new Roo.bootstrap.NavItem(cfg);
4396 cn.parentId = this.id;
4397 cn.onRender(this.el, null);
4401 * register a Navigation item
4402 * @param {Roo.bootstrap.NavItem} the navitem to add
4404 register : function(item)
4406 this.navItems.push( item);
4407 item.navId = this.navId;
4412 * clear all the Navigation item
4415 clearAll : function()
4418 this.el.dom.innerHTML = '';
4421 getNavItem: function(tabId)
4424 Roo.each(this.navItems, function(e) {
4425 if (e.tabId == tabId) {
4435 setActiveNext : function()
4437 var i = this.indexOfNav(this.getActive());
4438 if (i > this.navItems.length) {
4441 this.setActiveItem(this.navItems[i+1]);
4443 setActivePrev : function()
4445 var i = this.indexOfNav(this.getActive());
4449 this.setActiveItem(this.navItems[i-1]);
4451 clearWasActive : function(except) {
4452 Roo.each(this.navItems, function(e) {
4453 if (e.tabId != except.tabId && e.was_active) {
4454 e.was_active = false;
4461 getWasActive : function ()
4464 Roo.each(this.navItems, function(e) {
4479 Roo.apply(Roo.bootstrap.NavGroup, {
4483 * register a Navigation Group
4484 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4486 register : function(navgrp)
4488 this.groups[navgrp.navId] = navgrp;
4492 * fetch a Navigation Group based on the navigation ID
4493 * @param {string} the navgroup to add
4494 * @returns {Roo.bootstrap.NavGroup} the navgroup
4496 get: function(navId) {
4497 if (typeof(this.groups[navId]) == 'undefined') {
4499 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4501 return this.groups[navId] ;
4516 * @class Roo.bootstrap.NavItem
4517 * @extends Roo.bootstrap.Component
4518 * Bootstrap Navbar.NavItem class
4519 * @cfg {String} href link to
4520 * @cfg {String} html content of button
4521 * @cfg {String} badge text inside badge
4522 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4523 * @cfg {String} glyphicon name of glyphicon
4524 * @cfg {String} icon name of font awesome icon
4525 * @cfg {Boolean} active Is item active
4526 * @cfg {Boolean} disabled Is item disabled
4528 * @cfg {Boolean} preventDefault (true | false) default false
4529 * @cfg {String} tabId the tab that this item activates.
4530 * @cfg {String} tagtype (a|span) render as a href or span?
4531 * @cfg {Boolean} animateRef (true|false) link to element default false
4534 * Create a new Navbar Item
4535 * @param {Object} config The config object
4537 Roo.bootstrap.NavItem = function(config){
4538 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4543 * The raw click event for the entire grid.
4544 * @param {Roo.EventObject} e
4549 * Fires when the active item active state changes
4550 * @param {Roo.bootstrap.NavItem} this
4551 * @param {boolean} state the new state
4557 * Fires when scroll to element
4558 * @param {Roo.bootstrap.NavItem} this
4559 * @param {Object} options
4560 * @param {Roo.EventObject} e
4568 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4576 preventDefault : false,
4583 getAutoCreate : function(){
4592 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4594 if (this.disabled) {
4595 cfg.cls += ' disabled';
4598 if (this.href || this.html || this.glyphicon || this.icon) {
4602 href : this.href || "#",
4603 html: this.html || ''
4606 if (this.tagtype == 'a') {
4607 cfg.cn[0].cls = 'nav-link';
4610 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4613 if(this.glyphicon) {
4614 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4619 cfg.cn[0].html += " <span class='caret'></span>";
4623 if (this.badge !== '') {
4625 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4633 initEvents: function()
4635 if (typeof (this.menu) != 'undefined') {
4636 this.menu.parentType = this.xtype;
4637 this.menu.triggerEl = this.el;
4638 this.menu = this.addxtype(Roo.apply({}, this.menu));
4641 this.el.select('a',true).on('click', this.onClick, this);
4643 if(this.tagtype == 'span'){
4644 this.el.select('span',true).on('click', this.onClick, this);
4647 // at this point parent should be available..
4648 this.parent().register(this);
4651 onClick : function(e)
4653 if (e.getTarget('.dropdown-menu-item')) {
4654 // did you click on a menu itemm.... - then don't trigger onclick..
4659 this.preventDefault ||
4662 Roo.log("NavItem - prevent Default?");
4666 if (this.disabled) {
4670 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4671 if (tg && tg.transition) {
4672 Roo.log("waiting for the transitionend");
4678 //Roo.log("fire event clicked");
4679 if(this.fireEvent('click', this, e) === false){
4683 if(this.tagtype == 'span'){
4687 //Roo.log(this.href);
4688 var ael = this.el.select('a',true).first();
4691 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4692 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4693 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4694 return; // ignore... - it's a 'hash' to another page.
4696 Roo.log("NavItem - prevent Default?");
4698 this.scrollToElement(e);
4702 var p = this.parent();
4704 if (['tabs','pills'].indexOf(p.type)!==-1) {
4705 if (typeof(p.setActiveItem) !== 'undefined') {
4706 p.setActiveItem(this);
4710 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4711 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4712 // remove the collapsed menu expand...
4713 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4717 isActive: function () {
4720 setActive : function(state, fire, is_was_active)
4722 if (this.active && !state && this.navId) {
4723 this.was_active = true;
4724 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4726 nv.clearWasActive(this);
4730 this.active = state;
4733 this.el.removeClass('active');
4734 } else if (!this.el.hasClass('active')) {
4735 this.el.addClass('active');
4738 this.fireEvent('changed', this, state);
4741 // show a panel if it's registered and related..
4743 if (!this.navId || !this.tabId || !state || is_was_active) {
4747 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4751 var pan = tg.getPanelByName(this.tabId);
4755 // if we can not flip to new panel - go back to old nav highlight..
4756 if (false == tg.showPanel(pan)) {
4757 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4759 var onav = nv.getWasActive();
4761 onav.setActive(true, false, true);
4770 // this should not be here...
4771 setDisabled : function(state)
4773 this.disabled = state;
4775 this.el.removeClass('disabled');
4776 } else if (!this.el.hasClass('disabled')) {
4777 this.el.addClass('disabled');
4783 * Fetch the element to display the tooltip on.
4784 * @return {Roo.Element} defaults to this.el
4786 tooltipEl : function()
4788 return this.el.select('' + this.tagtype + '', true).first();
4791 scrollToElement : function(e)
4793 var c = document.body;
4796 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4798 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4799 c = document.documentElement;
4802 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4808 var o = target.calcOffsetsTo(c);
4815 this.fireEvent('scrollto', this, options, e);
4817 Roo.get(c).scrollTo('top', options.value, true);
4830 * <span> icon </span>
4831 * <span> text </span>
4832 * <span>badge </span>
4836 * @class Roo.bootstrap.NavSidebarItem
4837 * @extends Roo.bootstrap.NavItem
4838 * Bootstrap Navbar.NavSidebarItem class
4839 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4840 * {Boolean} open is the menu open
4841 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4842 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4843 * {String} buttonSize (sm|md|lg)the extra classes for the button
4844 * {Boolean} showArrow show arrow next to the text (default true)
4846 * Create a new Navbar Button
4847 * @param {Object} config The config object
4849 Roo.bootstrap.NavSidebarItem = function(config){
4850 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4855 * The raw click event for the entire grid.
4856 * @param {Roo.EventObject} e
4861 * Fires when the active item active state changes
4862 * @param {Roo.bootstrap.NavSidebarItem} this
4863 * @param {boolean} state the new state
4871 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4873 badgeWeight : 'default',
4879 buttonWeight : 'default',
4885 getAutoCreate : function(){
4890 href : this.href || '#',
4896 if(this.buttonView){
4899 href : this.href || '#',
4900 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4913 cfg.cls += ' active';
4916 if (this.disabled) {
4917 cfg.cls += ' disabled';
4920 cfg.cls += ' open x-open';
4923 if (this.glyphicon || this.icon) {
4924 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4925 a.cn.push({ tag : 'i', cls : c }) ;
4928 if(!this.buttonView){
4931 html : this.html || ''
4938 if (this.badge !== '') {
4939 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4945 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4948 a.cls += ' dropdown-toggle treeview' ;
4954 initEvents : function()
4956 if (typeof (this.menu) != 'undefined') {
4957 this.menu.parentType = this.xtype;
4958 this.menu.triggerEl = this.el;
4959 this.menu = this.addxtype(Roo.apply({}, this.menu));
4962 this.el.on('click', this.onClick, this);
4964 if(this.badge !== ''){
4965 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4970 onClick : function(e)
4977 if(this.preventDefault){
4981 this.fireEvent('click', this);
4984 disable : function()
4986 this.setDisabled(true);
4991 this.setDisabled(false);
4994 setDisabled : function(state)
4996 if(this.disabled == state){
5000 this.disabled = state;
5003 this.el.addClass('disabled');
5007 this.el.removeClass('disabled');
5012 setActive : function(state)
5014 if(this.active == state){
5018 this.active = state;
5021 this.el.addClass('active');
5025 this.el.removeClass('active');
5030 isActive: function ()
5035 setBadge : function(str)
5041 this.badgeEl.dom.innerHTML = str;
5058 * @class Roo.bootstrap.Row
5059 * @extends Roo.bootstrap.Component
5060 * Bootstrap Row class (contains columns...)
5064 * @param {Object} config The config object
5067 Roo.bootstrap.Row = function(config){
5068 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5071 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5073 getAutoCreate : function(){
5092 * @class Roo.bootstrap.Element
5093 * @extends Roo.bootstrap.Component
5094 * Bootstrap Element class
5095 * @cfg {String} html contents of the element
5096 * @cfg {String} tag tag of the element
5097 * @cfg {String} cls class of the element
5098 * @cfg {Boolean} preventDefault (true|false) default false
5099 * @cfg {Boolean} clickable (true|false) default false
5102 * Create a new Element
5103 * @param {Object} config The config object
5106 Roo.bootstrap.Element = function(config){
5107 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5113 * When a element is chick
5114 * @param {Roo.bootstrap.Element} this
5115 * @param {Roo.EventObject} e
5121 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5126 preventDefault: false,
5129 getAutoCreate : function(){
5133 // cls: this.cls, double assign in parent class Component.js :: onRender
5140 initEvents: function()
5142 Roo.bootstrap.Element.superclass.initEvents.call(this);
5145 this.el.on('click', this.onClick, this);
5150 onClick : function(e)
5152 if(this.preventDefault){
5156 this.fireEvent('click', this, e);
5159 getValue : function()
5161 return this.el.dom.innerHTML;
5164 setValue : function(value)
5166 this.el.dom.innerHTML = value;
5181 * @class Roo.bootstrap.Pagination
5182 * @extends Roo.bootstrap.Component
5183 * Bootstrap Pagination class
5184 * @cfg {String} size xs | sm | md | lg
5185 * @cfg {Boolean} inverse false | true
5188 * Create a new Pagination
5189 * @param {Object} config The config object
5192 Roo.bootstrap.Pagination = function(config){
5193 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5196 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5202 getAutoCreate : function(){
5208 cfg.cls += ' inverse';
5214 cfg.cls += " " + this.cls;
5232 * @class Roo.bootstrap.PaginationItem
5233 * @extends Roo.bootstrap.Component
5234 * Bootstrap PaginationItem class
5235 * @cfg {String} html text
5236 * @cfg {String} href the link
5237 * @cfg {Boolean} preventDefault (true | false) default true
5238 * @cfg {Boolean} active (true | false) default false
5239 * @cfg {Boolean} disabled default false
5243 * Create a new PaginationItem
5244 * @param {Object} config The config object
5248 Roo.bootstrap.PaginationItem = function(config){
5249 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5254 * The raw click event for the entire grid.
5255 * @param {Roo.EventObject} e
5261 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5265 preventDefault: true,
5270 getAutoCreate : function(){
5276 href : this.href ? this.href : '#',
5277 html : this.html ? this.html : ''
5287 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5291 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5297 initEvents: function() {
5299 this.el.on('click', this.onClick, this);
5302 onClick : function(e)
5304 Roo.log('PaginationItem on click ');
5305 if(this.preventDefault){
5313 this.fireEvent('click', this, e);
5329 * @class Roo.bootstrap.Slider
5330 * @extends Roo.bootstrap.Component
5331 * Bootstrap Slider class
5334 * Create a new Slider
5335 * @param {Object} config The config object
5338 Roo.bootstrap.Slider = function(config){
5339 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5342 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5344 getAutoCreate : function(){
5348 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5352 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5364 * Ext JS Library 1.1.1
5365 * Copyright(c) 2006-2007, Ext JS, LLC.
5367 * Originally Released Under LGPL - original licence link has changed is not relivant.
5370 * <script type="text/javascript">
5375 * @class Roo.grid.ColumnModel
5376 * @extends Roo.util.Observable
5377 * This is the default implementation of a ColumnModel used by the Grid. It defines
5378 * the columns in the grid.
5381 var colModel = new Roo.grid.ColumnModel([
5382 {header: "Ticker", width: 60, sortable: true, locked: true},
5383 {header: "Company Name", width: 150, sortable: true},
5384 {header: "Market Cap.", width: 100, sortable: true},
5385 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5386 {header: "Employees", width: 100, sortable: true, resizable: false}
5391 * The config options listed for this class are options which may appear in each
5392 * individual column definition.
5393 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5395 * @param {Object} config An Array of column config objects. See this class's
5396 * config objects for details.
5398 Roo.grid.ColumnModel = function(config){
5400 * The config passed into the constructor
5402 this.config = config;
5405 // if no id, create one
5406 // if the column does not have a dataIndex mapping,
5407 // map it to the order it is in the config
5408 for(var i = 0, len = config.length; i < len; i++){
5410 if(typeof c.dataIndex == "undefined"){
5413 if(typeof c.renderer == "string"){
5414 c.renderer = Roo.util.Format[c.renderer];
5416 if(typeof c.id == "undefined"){
5419 if(c.editor && c.editor.xtype){
5420 c.editor = Roo.factory(c.editor, Roo.grid);
5422 if(c.editor && c.editor.isFormField){
5423 c.editor = new Roo.grid.GridEditor(c.editor);
5425 this.lookup[c.id] = c;
5429 * The width of columns which have no width specified (defaults to 100)
5432 this.defaultWidth = 100;
5435 * Default sortable of columns which have no sortable specified (defaults to false)
5438 this.defaultSortable = false;
5442 * @event widthchange
5443 * Fires when the width of a column changes.
5444 * @param {ColumnModel} this
5445 * @param {Number} columnIndex The column index
5446 * @param {Number} newWidth The new width
5448 "widthchange": true,
5450 * @event headerchange
5451 * Fires when the text of a header changes.
5452 * @param {ColumnModel} this
5453 * @param {Number} columnIndex The column index
5454 * @param {Number} newText The new header text
5456 "headerchange": true,
5458 * @event hiddenchange
5459 * Fires when a column is hidden or "unhidden".
5460 * @param {ColumnModel} this
5461 * @param {Number} columnIndex The column index
5462 * @param {Boolean} hidden true if hidden, false otherwise
5464 "hiddenchange": true,
5466 * @event columnmoved
5467 * Fires when a column is moved.
5468 * @param {ColumnModel} this
5469 * @param {Number} oldIndex
5470 * @param {Number} newIndex
5472 "columnmoved" : true,
5474 * @event columlockchange
5475 * Fires when a column's locked state is changed
5476 * @param {ColumnModel} this
5477 * @param {Number} colIndex
5478 * @param {Boolean} locked true if locked
5480 "columnlockchange" : true
5482 Roo.grid.ColumnModel.superclass.constructor.call(this);
5484 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5486 * @cfg {String} header The header text to display in the Grid view.
5489 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5490 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5491 * specified, the column's index is used as an index into the Record's data Array.
5494 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5495 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5498 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5499 * Defaults to the value of the {@link #defaultSortable} property.
5500 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5503 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5506 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5509 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5512 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5515 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5516 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5517 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5518 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5521 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5524 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5527 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5530 * @cfg {String} cursor (Optional)
5533 * @cfg {String} tooltip (Optional)
5536 * @cfg {Number} xs (Optional)
5539 * @cfg {Number} sm (Optional)
5542 * @cfg {Number} md (Optional)
5545 * @cfg {Number} lg (Optional)
5548 * Returns the id of the column at the specified index.
5549 * @param {Number} index The column index
5550 * @return {String} the id
5552 getColumnId : function(index){
5553 return this.config[index].id;
5557 * Returns the column for a specified id.
5558 * @param {String} id The column id
5559 * @return {Object} the column
5561 getColumnById : function(id){
5562 return this.lookup[id];
5567 * Returns the column for a specified dataIndex.
5568 * @param {String} dataIndex The column dataIndex
5569 * @return {Object|Boolean} the column or false if not found
5571 getColumnByDataIndex: function(dataIndex){
5572 var index = this.findColumnIndex(dataIndex);
5573 return index > -1 ? this.config[index] : false;
5577 * Returns the index for a specified column id.
5578 * @param {String} id The column id
5579 * @return {Number} the index, or -1 if not found
5581 getIndexById : function(id){
5582 for(var i = 0, len = this.config.length; i < len; i++){
5583 if(this.config[i].id == id){
5591 * Returns the index for a specified column dataIndex.
5592 * @param {String} dataIndex The column dataIndex
5593 * @return {Number} the index, or -1 if not found
5596 findColumnIndex : function(dataIndex){
5597 for(var i = 0, len = this.config.length; i < len; i++){
5598 if(this.config[i].dataIndex == dataIndex){
5606 moveColumn : function(oldIndex, newIndex){
5607 var c = this.config[oldIndex];
5608 this.config.splice(oldIndex, 1);
5609 this.config.splice(newIndex, 0, c);
5610 this.dataMap = null;
5611 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5614 isLocked : function(colIndex){
5615 return this.config[colIndex].locked === true;
5618 setLocked : function(colIndex, value, suppressEvent){
5619 if(this.isLocked(colIndex) == value){
5622 this.config[colIndex].locked = value;
5624 this.fireEvent("columnlockchange", this, colIndex, value);
5628 getTotalLockedWidth : function(){
5630 for(var i = 0; i < this.config.length; i++){
5631 if(this.isLocked(i) && !this.isHidden(i)){
5632 this.totalWidth += this.getColumnWidth(i);
5638 getLockedCount : function(){
5639 for(var i = 0, len = this.config.length; i < len; i++){
5640 if(!this.isLocked(i)){
5645 return this.config.length;
5649 * Returns the number of columns.
5652 getColumnCount : function(visibleOnly){
5653 if(visibleOnly === true){
5655 for(var i = 0, len = this.config.length; i < len; i++){
5656 if(!this.isHidden(i)){
5662 return this.config.length;
5666 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5667 * @param {Function} fn
5668 * @param {Object} scope (optional)
5669 * @return {Array} result
5671 getColumnsBy : function(fn, scope){
5673 for(var i = 0, len = this.config.length; i < len; i++){
5674 var c = this.config[i];
5675 if(fn.call(scope||this, c, i) === true){
5683 * Returns true if the specified column is sortable.
5684 * @param {Number} col The column index
5687 isSortable : function(col){
5688 if(typeof this.config[col].sortable == "undefined"){
5689 return this.defaultSortable;
5691 return this.config[col].sortable;
5695 * Returns the rendering (formatting) function defined for the column.
5696 * @param {Number} col The column index.
5697 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5699 getRenderer : function(col){
5700 if(!this.config[col].renderer){
5701 return Roo.grid.ColumnModel.defaultRenderer;
5703 return this.config[col].renderer;
5707 * Sets the rendering (formatting) function for a column.
5708 * @param {Number} col The column index
5709 * @param {Function} fn The function to use to process the cell's raw data
5710 * to return HTML markup for the grid view. The render function is called with
5711 * the following parameters:<ul>
5712 * <li>Data value.</li>
5713 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5714 * <li>css A CSS style string to apply to the table cell.</li>
5715 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5716 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5717 * <li>Row index</li>
5718 * <li>Column index</li>
5719 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5721 setRenderer : function(col, fn){
5722 this.config[col].renderer = fn;
5726 * Returns the width for the specified column.
5727 * @param {Number} col The column index
5730 getColumnWidth : function(col){
5731 return this.config[col].width * 1 || this.defaultWidth;
5735 * Sets the width for a column.
5736 * @param {Number} col The column index
5737 * @param {Number} width The new width
5739 setColumnWidth : function(col, width, suppressEvent){
5740 this.config[col].width = width;
5741 this.totalWidth = null;
5743 this.fireEvent("widthchange", this, col, width);
5748 * Returns the total width of all columns.
5749 * @param {Boolean} includeHidden True to include hidden column widths
5752 getTotalWidth : function(includeHidden){
5753 if(!this.totalWidth){
5754 this.totalWidth = 0;
5755 for(var i = 0, len = this.config.length; i < len; i++){
5756 if(includeHidden || !this.isHidden(i)){
5757 this.totalWidth += this.getColumnWidth(i);
5761 return this.totalWidth;
5765 * Returns the header for the specified column.
5766 * @param {Number} col The column index
5769 getColumnHeader : function(col){
5770 return this.config[col].header;
5774 * Sets the header for a column.
5775 * @param {Number} col The column index
5776 * @param {String} header The new header
5778 setColumnHeader : function(col, header){
5779 this.config[col].header = header;
5780 this.fireEvent("headerchange", this, col, header);
5784 * Returns the tooltip for the specified column.
5785 * @param {Number} col The column index
5788 getColumnTooltip : function(col){
5789 return this.config[col].tooltip;
5792 * Sets the tooltip for a column.
5793 * @param {Number} col The column index
5794 * @param {String} tooltip The new tooltip
5796 setColumnTooltip : function(col, tooltip){
5797 this.config[col].tooltip = tooltip;
5801 * Returns the dataIndex for the specified column.
5802 * @param {Number} col The column index
5805 getDataIndex : function(col){
5806 return this.config[col].dataIndex;
5810 * Sets the dataIndex for a column.
5811 * @param {Number} col The column index
5812 * @param {Number} dataIndex The new dataIndex
5814 setDataIndex : function(col, dataIndex){
5815 this.config[col].dataIndex = dataIndex;
5821 * Returns true if the cell is editable.
5822 * @param {Number} colIndex The column index
5823 * @param {Number} rowIndex The row index - this is nto actually used..?
5826 isCellEditable : function(colIndex, rowIndex){
5827 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5831 * Returns the editor defined for the cell/column.
5832 * return false or null to disable editing.
5833 * @param {Number} colIndex The column index
5834 * @param {Number} rowIndex The row index
5837 getCellEditor : function(colIndex, rowIndex){
5838 return this.config[colIndex].editor;
5842 * Sets if a column is editable.
5843 * @param {Number} col The column index
5844 * @param {Boolean} editable True if the column is editable
5846 setEditable : function(col, editable){
5847 this.config[col].editable = editable;
5852 * Returns true if the column is hidden.
5853 * @param {Number} colIndex The column index
5856 isHidden : function(colIndex){
5857 return this.config[colIndex].hidden;
5862 * Returns true if the column width cannot be changed
5864 isFixed : function(colIndex){
5865 return this.config[colIndex].fixed;
5869 * Returns true if the column can be resized
5872 isResizable : function(colIndex){
5873 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5876 * Sets if a column is hidden.
5877 * @param {Number} colIndex The column index
5878 * @param {Boolean} hidden True if the column is hidden
5880 setHidden : function(colIndex, hidden){
5881 this.config[colIndex].hidden = hidden;
5882 this.totalWidth = null;
5883 this.fireEvent("hiddenchange", this, colIndex, hidden);
5887 * Sets the editor for a column.
5888 * @param {Number} col The column index
5889 * @param {Object} editor The editor object
5891 setEditor : function(col, editor){
5892 this.config[col].editor = editor;
5896 Roo.grid.ColumnModel.defaultRenderer = function(value)
5898 if(typeof value == "object") {
5901 if(typeof value == "string" && value.length < 1){
5905 return String.format("{0}", value);
5908 // Alias for backwards compatibility
5909 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5912 * Ext JS Library 1.1.1
5913 * Copyright(c) 2006-2007, Ext JS, LLC.
5915 * Originally Released Under LGPL - original licence link has changed is not relivant.
5918 * <script type="text/javascript">
5922 * @class Roo.LoadMask
5923 * A simple utility class for generically masking elements while loading data. If the element being masked has
5924 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5925 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5926 * element's UpdateManager load indicator and will be destroyed after the initial load.
5928 * Create a new LoadMask
5929 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5930 * @param {Object} config The config object
5932 Roo.LoadMask = function(el, config){
5933 this.el = Roo.get(el);
5934 Roo.apply(this, config);
5936 this.store.on('beforeload', this.onBeforeLoad, this);
5937 this.store.on('load', this.onLoad, this);
5938 this.store.on('loadexception', this.onLoadException, this);
5939 this.removeMask = false;
5941 var um = this.el.getUpdateManager();
5942 um.showLoadIndicator = false; // disable the default indicator
5943 um.on('beforeupdate', this.onBeforeLoad, this);
5944 um.on('update', this.onLoad, this);
5945 um.on('failure', this.onLoad, this);
5946 this.removeMask = true;
5950 Roo.LoadMask.prototype = {
5952 * @cfg {Boolean} removeMask
5953 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5954 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5958 * The text to display in a centered loading message box (defaults to 'Loading...')
5962 * @cfg {String} msgCls
5963 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5965 msgCls : 'x-mask-loading',
5968 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5974 * Disables the mask to prevent it from being displayed
5976 disable : function(){
5977 this.disabled = true;
5981 * Enables the mask so that it can be displayed
5983 enable : function(){
5984 this.disabled = false;
5987 onLoadException : function()
5991 if (typeof(arguments[3]) != 'undefined') {
5992 Roo.MessageBox.alert("Error loading",arguments[3]);
5996 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5997 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6004 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6009 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6013 onBeforeLoad : function(){
6015 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6020 destroy : function(){
6022 this.store.un('beforeload', this.onBeforeLoad, this);
6023 this.store.un('load', this.onLoad, this);
6024 this.store.un('loadexception', this.onLoadException, this);
6026 var um = this.el.getUpdateManager();
6027 um.un('beforeupdate', this.onBeforeLoad, this);
6028 um.un('update', this.onLoad, this);
6029 um.un('failure', this.onLoad, this);
6040 * @class Roo.bootstrap.Table
6041 * @extends Roo.bootstrap.Component
6042 * Bootstrap Table class
6043 * @cfg {String} cls table class
6044 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6045 * @cfg {String} bgcolor Specifies the background color for a table
6046 * @cfg {Number} border Specifies whether the table cells should have borders or not
6047 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6048 * @cfg {Number} cellspacing Specifies the space between cells
6049 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6050 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6051 * @cfg {String} sortable Specifies that the table should be sortable
6052 * @cfg {String} summary Specifies a summary of the content of a table
6053 * @cfg {Number} width Specifies the width of a table
6054 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6056 * @cfg {boolean} striped Should the rows be alternative striped
6057 * @cfg {boolean} bordered Add borders to the table
6058 * @cfg {boolean} hover Add hover highlighting
6059 * @cfg {boolean} condensed Format condensed
6060 * @cfg {boolean} responsive Format condensed
6061 * @cfg {Boolean} loadMask (true|false) default false
6062 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6063 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6064 * @cfg {Boolean} rowSelection (true|false) default false
6065 * @cfg {Boolean} cellSelection (true|false) default false
6066 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6067 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6068 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6069 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6073 * Create a new Table
6074 * @param {Object} config The config object
6077 Roo.bootstrap.Table = function(config){
6078 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6083 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6084 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6085 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6086 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6088 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6090 this.sm.grid = this;
6091 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6092 this.sm = this.selModel;
6093 this.sm.xmodule = this.xmodule || false;
6096 if (this.cm && typeof(this.cm.config) == 'undefined') {
6097 this.colModel = new Roo.grid.ColumnModel(this.cm);
6098 this.cm = this.colModel;
6099 this.cm.xmodule = this.xmodule || false;
6102 this.store= Roo.factory(this.store, Roo.data);
6103 this.ds = this.store;
6104 this.ds.xmodule = this.xmodule || false;
6107 if (this.footer && this.store) {
6108 this.footer.dataSource = this.ds;
6109 this.footer = Roo.factory(this.footer);
6116 * Fires when a cell is clicked
6117 * @param {Roo.bootstrap.Table} this
6118 * @param {Roo.Element} el
6119 * @param {Number} rowIndex
6120 * @param {Number} columnIndex
6121 * @param {Roo.EventObject} e
6125 * @event celldblclick
6126 * Fires when a cell is double clicked
6127 * @param {Roo.bootstrap.Table} this
6128 * @param {Roo.Element} el
6129 * @param {Number} rowIndex
6130 * @param {Number} columnIndex
6131 * @param {Roo.EventObject} e
6133 "celldblclick" : true,
6136 * Fires when a row is clicked
6137 * @param {Roo.bootstrap.Table} this
6138 * @param {Roo.Element} el
6139 * @param {Number} rowIndex
6140 * @param {Roo.EventObject} e
6144 * @event rowdblclick
6145 * Fires when a row is double clicked
6146 * @param {Roo.bootstrap.Table} this
6147 * @param {Roo.Element} el
6148 * @param {Number} rowIndex
6149 * @param {Roo.EventObject} e
6151 "rowdblclick" : true,
6154 * Fires when a mouseover occur
6155 * @param {Roo.bootstrap.Table} this
6156 * @param {Roo.Element} el
6157 * @param {Number} rowIndex
6158 * @param {Number} columnIndex
6159 * @param {Roo.EventObject} e
6164 * Fires when a mouseout occur
6165 * @param {Roo.bootstrap.Table} this
6166 * @param {Roo.Element} el
6167 * @param {Number} rowIndex
6168 * @param {Number} columnIndex
6169 * @param {Roo.EventObject} e
6174 * Fires when a row is rendered, so you can change add a style to it.
6175 * @param {Roo.bootstrap.Table} this
6176 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6180 * @event rowsrendered
6181 * Fires when all the rows have been rendered
6182 * @param {Roo.bootstrap.Table} this
6184 'rowsrendered' : true,
6186 * @event contextmenu
6187 * The raw contextmenu event for the entire grid.
6188 * @param {Roo.EventObject} e
6190 "contextmenu" : true,
6192 * @event rowcontextmenu
6193 * Fires when a row is right clicked
6194 * @param {Roo.bootstrap.Table} this
6195 * @param {Number} rowIndex
6196 * @param {Roo.EventObject} e
6198 "rowcontextmenu" : true,
6200 * @event cellcontextmenu
6201 * Fires when a cell is right clicked
6202 * @param {Roo.bootstrap.Table} this
6203 * @param {Number} rowIndex
6204 * @param {Number} cellIndex
6205 * @param {Roo.EventObject} e
6207 "cellcontextmenu" : true,
6209 * @event headercontextmenu
6210 * Fires when a header is right clicked
6211 * @param {Roo.bootstrap.Table} this
6212 * @param {Number} columnIndex
6213 * @param {Roo.EventObject} e
6215 "headercontextmenu" : true
6219 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6245 rowSelection : false,
6246 cellSelection : false,
6249 // Roo.Element - the tbody
6251 // Roo.Element - thead element
6254 container: false, // used by gridpanel...
6260 auto_hide_footer : false,
6262 getAutoCreate : function()
6264 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6271 if (this.scrollBody) {
6272 cfg.cls += ' table-body-fixed';
6275 cfg.cls += ' table-striped';
6279 cfg.cls += ' table-hover';
6281 if (this.bordered) {
6282 cfg.cls += ' table-bordered';
6284 if (this.condensed) {
6285 cfg.cls += ' table-condensed';
6287 if (this.responsive) {
6288 cfg.cls += ' table-responsive';
6292 cfg.cls+= ' ' +this.cls;
6295 // this lot should be simplifed...
6308 ].forEach(function(k) {
6316 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6319 if(this.store || this.cm){
6320 if(this.headerShow){
6321 cfg.cn.push(this.renderHeader());
6324 cfg.cn.push(this.renderBody());
6326 if(this.footerShow){
6327 cfg.cn.push(this.renderFooter());
6329 // where does this come from?
6330 //cfg.cls+= ' TableGrid';
6333 return { cn : [ cfg ] };
6336 initEvents : function()
6338 if(!this.store || !this.cm){
6341 if (this.selModel) {
6342 this.selModel.initEvents();
6346 //Roo.log('initEvents with ds!!!!');
6348 this.mainBody = this.el.select('tbody', true).first();
6349 this.mainHead = this.el.select('thead', true).first();
6350 this.mainFoot = this.el.select('tfoot', true).first();
6356 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6357 e.on('click', _this.sort, _this);
6360 this.mainBody.on("click", this.onClick, this);
6361 this.mainBody.on("dblclick", this.onDblClick, this);
6363 // why is this done????? = it breaks dialogs??
6364 //this.parent().el.setStyle('position', 'relative');
6368 this.footer.parentId = this.id;
6369 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6372 this.el.select('tfoot tr td').first().addClass('hide');
6377 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6380 this.store.on('load', this.onLoad, this);
6381 this.store.on('beforeload', this.onBeforeLoad, this);
6382 this.store.on('update', this.onUpdate, this);
6383 this.store.on('add', this.onAdd, this);
6384 this.store.on("clear", this.clear, this);
6386 this.el.on("contextmenu", this.onContextMenu, this);
6388 this.mainBody.on('scroll', this.onBodyScroll, this);
6390 this.cm.on("headerchange", this.onHeaderChange, this);
6392 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6396 onContextMenu : function(e, t)
6398 this.processEvent("contextmenu", e);
6401 processEvent : function(name, e)
6403 if (name != 'touchstart' ) {
6404 this.fireEvent(name, e);
6407 var t = e.getTarget();
6409 var cell = Roo.get(t);
6415 if(cell.findParent('tfoot', false, true)){
6419 if(cell.findParent('thead', false, true)){
6421 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6422 cell = Roo.get(t).findParent('th', false, true);
6424 Roo.log("failed to find th in thead?");
6425 Roo.log(e.getTarget());
6430 var cellIndex = cell.dom.cellIndex;
6432 var ename = name == 'touchstart' ? 'click' : name;
6433 this.fireEvent("header" + ename, this, cellIndex, e);
6438 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6439 cell = Roo.get(t).findParent('td', false, true);
6441 Roo.log("failed to find th in tbody?");
6442 Roo.log(e.getTarget());
6447 var row = cell.findParent('tr', false, true);
6448 var cellIndex = cell.dom.cellIndex;
6449 var rowIndex = row.dom.rowIndex - 1;
6453 this.fireEvent("row" + name, this, rowIndex, e);
6457 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6463 onMouseover : function(e, el)
6465 var cell = Roo.get(el);
6471 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6472 cell = cell.findParent('td', false, true);
6475 var row = cell.findParent('tr', false, true);
6476 var cellIndex = cell.dom.cellIndex;
6477 var rowIndex = row.dom.rowIndex - 1; // start from 0
6479 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6483 onMouseout : function(e, el)
6485 var cell = Roo.get(el);
6491 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6492 cell = cell.findParent('td', false, true);
6495 var row = cell.findParent('tr', false, true);
6496 var cellIndex = cell.dom.cellIndex;
6497 var rowIndex = row.dom.rowIndex - 1; // start from 0
6499 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6503 onClick : function(e, el)
6505 var cell = Roo.get(el);
6507 if(!cell || (!this.cellSelection && !this.rowSelection)){
6511 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6512 cell = cell.findParent('td', false, true);
6515 if(!cell || typeof(cell) == 'undefined'){
6519 var row = cell.findParent('tr', false, true);
6521 if(!row || typeof(row) == 'undefined'){
6525 var cellIndex = cell.dom.cellIndex;
6526 var rowIndex = this.getRowIndex(row);
6528 // why??? - should these not be based on SelectionModel?
6529 if(this.cellSelection){
6530 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6533 if(this.rowSelection){
6534 this.fireEvent('rowclick', this, row, rowIndex, e);
6540 onDblClick : function(e,el)
6542 var cell = Roo.get(el);
6544 if(!cell || (!this.cellSelection && !this.rowSelection)){
6548 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6549 cell = cell.findParent('td', false, true);
6552 if(!cell || typeof(cell) == 'undefined'){
6556 var row = cell.findParent('tr', false, true);
6558 if(!row || typeof(row) == 'undefined'){
6562 var cellIndex = cell.dom.cellIndex;
6563 var rowIndex = this.getRowIndex(row);
6565 if(this.cellSelection){
6566 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6569 if(this.rowSelection){
6570 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6574 sort : function(e,el)
6576 var col = Roo.get(el);
6578 if(!col.hasClass('sortable')){
6582 var sort = col.attr('sort');
6585 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6589 this.store.sortInfo = {field : sort, direction : dir};
6592 Roo.log("calling footer first");
6593 this.footer.onClick('first');
6596 this.store.load({ params : { start : 0 } });
6600 renderHeader : function()
6608 this.totalWidth = 0;
6610 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6612 var config = cm.config[i];
6616 cls : 'x-hcol-' + i,
6618 html: cm.getColumnHeader(i)
6623 if(typeof(config.sortable) != 'undefined' && config.sortable){
6625 c.html = '<i class="glyphicon"></i>' + c.html;
6628 if(typeof(config.lgHeader) != 'undefined'){
6629 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6632 if(typeof(config.mdHeader) != 'undefined'){
6633 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6636 if(typeof(config.smHeader) != 'undefined'){
6637 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6640 if(typeof(config.xsHeader) != 'undefined'){
6641 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6648 if(typeof(config.tooltip) != 'undefined'){
6649 c.tooltip = config.tooltip;
6652 if(typeof(config.colspan) != 'undefined'){
6653 c.colspan = config.colspan;
6656 if(typeof(config.hidden) != 'undefined' && config.hidden){
6657 c.style += ' display:none;';
6660 if(typeof(config.dataIndex) != 'undefined'){
6661 c.sort = config.dataIndex;
6666 if(typeof(config.align) != 'undefined' && config.align.length){
6667 c.style += ' text-align:' + config.align + ';';
6670 if(typeof(config.width) != 'undefined'){
6671 c.style += ' width:' + config.width + 'px;';
6672 this.totalWidth += config.width;
6674 this.totalWidth += 100; // assume minimum of 100 per column?
6677 if(typeof(config.cls) != 'undefined'){
6678 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6681 ['xs','sm','md','lg'].map(function(size){
6683 if(typeof(config[size]) == 'undefined'){
6687 if (!config[size]) { // 0 = hidden
6688 c.cls += ' hidden-' + size;
6692 c.cls += ' col-' + size + '-' + config[size];
6702 renderBody : function()
6712 colspan : this.cm.getColumnCount()
6722 renderFooter : function()
6732 colspan : this.cm.getColumnCount()
6746 // Roo.log('ds onload');
6751 var ds = this.store;
6753 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6754 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6755 if (_this.store.sortInfo) {
6757 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6758 e.select('i', true).addClass(['glyphicon-arrow-up']);
6761 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6762 e.select('i', true).addClass(['glyphicon-arrow-down']);
6767 var tbody = this.mainBody;
6769 if(ds.getCount() > 0){
6770 ds.data.each(function(d,rowIndex){
6771 var row = this.renderRow(cm, ds, rowIndex);
6773 tbody.createChild(row);
6777 if(row.cellObjects.length){
6778 Roo.each(row.cellObjects, function(r){
6779 _this.renderCellObject(r);
6786 var tfoot = this.el.select('tfoot', true).first();
6788 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6790 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6792 var total = this.ds.getTotalCount();
6794 if(this.footer.pageSize < total){
6795 this.mainFoot.show();
6799 Roo.each(this.el.select('tbody td', true).elements, function(e){
6800 e.on('mouseover', _this.onMouseover, _this);
6803 Roo.each(this.el.select('tbody td', true).elements, function(e){
6804 e.on('mouseout', _this.onMouseout, _this);
6806 this.fireEvent('rowsrendered', this);
6812 onUpdate : function(ds,record)
6814 this.refreshRow(record);
6818 onRemove : function(ds, record, index, isUpdate){
6819 if(isUpdate !== true){
6820 this.fireEvent("beforerowremoved", this, index, record);
6822 var bt = this.mainBody.dom;
6824 var rows = this.el.select('tbody > tr', true).elements;
6826 if(typeof(rows[index]) != 'undefined'){
6827 bt.removeChild(rows[index].dom);
6830 // if(bt.rows[index]){
6831 // bt.removeChild(bt.rows[index]);
6834 if(isUpdate !== true){
6835 //this.stripeRows(index);
6836 //this.syncRowHeights(index, index);
6838 this.fireEvent("rowremoved", this, index, record);
6842 onAdd : function(ds, records, rowIndex)
6844 //Roo.log('on Add called');
6845 // - note this does not handle multiple adding very well..
6846 var bt = this.mainBody.dom;
6847 for (var i =0 ; i < records.length;i++) {
6848 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6849 //Roo.log(records[i]);
6850 //Roo.log(this.store.getAt(rowIndex+i));
6851 this.insertRow(this.store, rowIndex + i, false);
6858 refreshRow : function(record){
6859 var ds = this.store, index;
6860 if(typeof record == 'number'){
6862 record = ds.getAt(index);
6864 index = ds.indexOf(record);
6866 this.insertRow(ds, index, true);
6868 this.onRemove(ds, record, index+1, true);
6870 //this.syncRowHeights(index, index);
6872 this.fireEvent("rowupdated", this, index, record);
6875 insertRow : function(dm, rowIndex, isUpdate){
6878 this.fireEvent("beforerowsinserted", this, rowIndex);
6880 //var s = this.getScrollState();
6881 var row = this.renderRow(this.cm, this.store, rowIndex);
6882 // insert before rowIndex..
6883 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6887 if(row.cellObjects.length){
6888 Roo.each(row.cellObjects, function(r){
6889 _this.renderCellObject(r);
6894 this.fireEvent("rowsinserted", this, rowIndex);
6895 //this.syncRowHeights(firstRow, lastRow);
6896 //this.stripeRows(firstRow);
6903 getRowDom : function(rowIndex)
6905 var rows = this.el.select('tbody > tr', true).elements;
6907 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6910 // returns the object tree for a tr..
6913 renderRow : function(cm, ds, rowIndex)
6915 var d = ds.getAt(rowIndex);
6919 cls : 'x-row-' + rowIndex,
6923 var cellObjects = [];
6925 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6926 var config = cm.config[i];
6928 var renderer = cm.getRenderer(i);
6932 if(typeof(renderer) !== 'undefined'){
6933 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6935 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6936 // and are rendered into the cells after the row is rendered - using the id for the element.
6938 if(typeof(value) === 'object'){
6948 rowIndex : rowIndex,
6953 this.fireEvent('rowclass', this, rowcfg);
6957 cls : rowcfg.rowClass + ' x-col-' + i,
6959 html: (typeof(value) === 'object') ? '' : value
6966 if(typeof(config.colspan) != 'undefined'){
6967 td.colspan = config.colspan;
6970 if(typeof(config.hidden) != 'undefined' && config.hidden){
6971 td.style += ' display:none;';
6974 if(typeof(config.align) != 'undefined' && config.align.length){
6975 td.style += ' text-align:' + config.align + ';';
6977 if(typeof(config.valign) != 'undefined' && config.valign.length){
6978 td.style += ' vertical-align:' + config.valign + ';';
6981 if(typeof(config.width) != 'undefined'){
6982 td.style += ' width:' + config.width + 'px;';
6985 if(typeof(config.cursor) != 'undefined'){
6986 td.style += ' cursor:' + config.cursor + ';';
6989 if(typeof(config.cls) != 'undefined'){
6990 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6993 ['xs','sm','md','lg'].map(function(size){
6995 if(typeof(config[size]) == 'undefined'){
6999 if (!config[size]) { // 0 = hidden
7000 td.cls += ' hidden-' + size;
7004 td.cls += ' col-' + size + '-' + config[size];
7012 row.cellObjects = cellObjects;
7020 onBeforeLoad : function()
7029 this.el.select('tbody', true).first().dom.innerHTML = '';
7032 * Show or hide a row.
7033 * @param {Number} rowIndex to show or hide
7034 * @param {Boolean} state hide
7036 setRowVisibility : function(rowIndex, state)
7038 var bt = this.mainBody.dom;
7040 var rows = this.el.select('tbody > tr', true).elements;
7042 if(typeof(rows[rowIndex]) == 'undefined'){
7045 rows[rowIndex].dom.style.display = state ? '' : 'none';
7049 getSelectionModel : function(){
7051 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7053 return this.selModel;
7056 * Render the Roo.bootstrap object from renderder
7058 renderCellObject : function(r)
7062 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7064 var t = r.cfg.render(r.container);
7067 Roo.each(r.cfg.cn, function(c){
7069 container: t.getChildContainer(),
7072 _this.renderCellObject(child);
7077 getRowIndex : function(row)
7081 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7092 * Returns the grid's underlying element = used by panel.Grid
7093 * @return {Element} The element
7095 getGridEl : function(){
7099 * Forces a resize - used by panel.Grid
7100 * @return {Element} The element
7102 autoSize : function()
7104 //var ctr = Roo.get(this.container.dom.parentElement);
7105 var ctr = Roo.get(this.el.dom);
7107 var thd = this.getGridEl().select('thead',true).first();
7108 var tbd = this.getGridEl().select('tbody', true).first();
7109 var tfd = this.getGridEl().select('tfoot', true).first();
7111 var cw = ctr.getWidth();
7115 tbd.setSize(ctr.getWidth(),
7116 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7118 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7121 cw = Math.max(cw, this.totalWidth);
7122 this.getGridEl().select('tr',true).setWidth(cw);
7123 // resize 'expandable coloumn?
7125 return; // we doe not have a view in this design..
7128 onBodyScroll: function()
7130 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7132 this.mainHead.setStyle({
7133 'position' : 'relative',
7134 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7140 var scrollHeight = this.mainBody.dom.scrollHeight;
7142 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7144 var height = this.mainBody.getHeight();
7146 if(scrollHeight - height == scrollTop) {
7148 var total = this.ds.getTotalCount();
7150 if(this.footer.cursor + this.footer.pageSize < total){
7152 this.footer.ds.load({
7154 start : this.footer.cursor + this.footer.pageSize,
7155 limit : this.footer.pageSize
7165 onHeaderChange : function()
7167 var header = this.renderHeader();
7168 var table = this.el.select('table', true).first();
7170 this.mainHead.remove();
7171 this.mainHead = table.createChild(header, this.mainBody, false);
7174 onHiddenChange : function(colModel, colIndex, hidden)
7176 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7177 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7179 this.CSS.updateRule(thSelector, "display", "");
7180 this.CSS.updateRule(tdSelector, "display", "");
7183 this.CSS.updateRule(thSelector, "display", "none");
7184 this.CSS.updateRule(tdSelector, "display", "none");
7187 this.onHeaderChange();
7191 setColumnWidth: function(col_index, width)
7193 // width = "md-2 xs-2..."
7194 if(!this.colModel.config[col_index]) {
7198 var w = width.split(" ");
7200 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7202 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7205 for(var j = 0; j < w.length; j++) {
7211 var size_cls = w[j].split("-");
7213 if(!Number.isInteger(size_cls[1] * 1)) {
7217 if(!this.colModel.config[col_index][size_cls[0]]) {
7221 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7225 h_row[0].classList.replace(
7226 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7227 "col-"+size_cls[0]+"-"+size_cls[1]
7230 for(var i = 0; i < rows.length; i++) {
7232 var size_cls = w[j].split("-");
7234 if(!Number.isInteger(size_cls[1] * 1)) {
7238 if(!this.colModel.config[col_index][size_cls[0]]) {
7242 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7246 rows[i].classList.replace(
7247 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7248 "col-"+size_cls[0]+"-"+size_cls[1]
7252 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7267 * @class Roo.bootstrap.TableCell
7268 * @extends Roo.bootstrap.Component
7269 * Bootstrap TableCell class
7270 * @cfg {String} html cell contain text
7271 * @cfg {String} cls cell class
7272 * @cfg {String} tag cell tag (td|th) default td
7273 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7274 * @cfg {String} align Aligns the content in a cell
7275 * @cfg {String} axis Categorizes cells
7276 * @cfg {String} bgcolor Specifies the background color of a cell
7277 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7278 * @cfg {Number} colspan Specifies the number of columns a cell should span
7279 * @cfg {String} headers Specifies one or more header cells a cell is related to
7280 * @cfg {Number} height Sets the height of a cell
7281 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7282 * @cfg {Number} rowspan Sets the number of rows a cell should span
7283 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7284 * @cfg {String} valign Vertical aligns the content in a cell
7285 * @cfg {Number} width Specifies the width of a cell
7288 * Create a new TableCell
7289 * @param {Object} config The config object
7292 Roo.bootstrap.TableCell = function(config){
7293 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7296 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7316 getAutoCreate : function(){
7317 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7337 cfg.align=this.align
7343 cfg.bgcolor=this.bgcolor
7346 cfg.charoff=this.charoff
7349 cfg.colspan=this.colspan
7352 cfg.headers=this.headers
7355 cfg.height=this.height
7358 cfg.nowrap=this.nowrap
7361 cfg.rowspan=this.rowspan
7364 cfg.scope=this.scope
7367 cfg.valign=this.valign
7370 cfg.width=this.width
7389 * @class Roo.bootstrap.TableRow
7390 * @extends Roo.bootstrap.Component
7391 * Bootstrap TableRow class
7392 * @cfg {String} cls row class
7393 * @cfg {String} align Aligns the content in a table row
7394 * @cfg {String} bgcolor Specifies a background color for a table row
7395 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7396 * @cfg {String} valign Vertical aligns the content in a table row
7399 * Create a new TableRow
7400 * @param {Object} config The config object
7403 Roo.bootstrap.TableRow = function(config){
7404 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7407 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7415 getAutoCreate : function(){
7416 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7426 cfg.align = this.align;
7429 cfg.bgcolor = this.bgcolor;
7432 cfg.charoff = this.charoff;
7435 cfg.valign = this.valign;
7453 * @class Roo.bootstrap.TableBody
7454 * @extends Roo.bootstrap.Component
7455 * Bootstrap TableBody class
7456 * @cfg {String} cls element class
7457 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7458 * @cfg {String} align Aligns the content inside the element
7459 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7460 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7463 * Create a new TableBody
7464 * @param {Object} config The config object
7467 Roo.bootstrap.TableBody = function(config){
7468 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7471 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7479 getAutoCreate : function(){
7480 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7494 cfg.align = this.align;
7497 cfg.charoff = this.charoff;
7500 cfg.valign = this.valign;
7507 // initEvents : function()
7514 // this.store = Roo.factory(this.store, Roo.data);
7515 // this.store.on('load', this.onLoad, this);
7517 // this.store.load();
7521 // onLoad: function ()
7523 // this.fireEvent('load', this);
7533 * Ext JS Library 1.1.1
7534 * Copyright(c) 2006-2007, Ext JS, LLC.
7536 * Originally Released Under LGPL - original licence link has changed is not relivant.
7539 * <script type="text/javascript">
7542 // as we use this in bootstrap.
7543 Roo.namespace('Roo.form');
7545 * @class Roo.form.Action
7546 * Internal Class used to handle form actions
7548 * @param {Roo.form.BasicForm} el The form element or its id
7549 * @param {Object} config Configuration options
7554 // define the action interface
7555 Roo.form.Action = function(form, options){
7557 this.options = options || {};
7560 * Client Validation Failed
7563 Roo.form.Action.CLIENT_INVALID = 'client';
7565 * Server Validation Failed
7568 Roo.form.Action.SERVER_INVALID = 'server';
7570 * Connect to Server Failed
7573 Roo.form.Action.CONNECT_FAILURE = 'connect';
7575 * Reading Data from Server Failed
7578 Roo.form.Action.LOAD_FAILURE = 'load';
7580 Roo.form.Action.prototype = {
7582 failureType : undefined,
7583 response : undefined,
7587 run : function(options){
7592 success : function(response){
7597 handleResponse : function(response){
7601 // default connection failure
7602 failure : function(response){
7604 this.response = response;
7605 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7606 this.form.afterAction(this, false);
7609 processResponse : function(response){
7610 this.response = response;
7611 if(!response.responseText){
7614 this.result = this.handleResponse(response);
7618 // utility functions used internally
7619 getUrl : function(appendParams){
7620 var url = this.options.url || this.form.url || this.form.el.dom.action;
7622 var p = this.getParams();
7624 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7630 getMethod : function(){
7631 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7634 getParams : function(){
7635 var bp = this.form.baseParams;
7636 var p = this.options.params;
7638 if(typeof p == "object"){
7639 p = Roo.urlEncode(Roo.applyIf(p, bp));
7640 }else if(typeof p == 'string' && bp){
7641 p += '&' + Roo.urlEncode(bp);
7644 p = Roo.urlEncode(bp);
7649 createCallback : function(){
7651 success: this.success,
7652 failure: this.failure,
7654 timeout: (this.form.timeout*1000),
7655 upload: this.form.fileUpload ? this.success : undefined
7660 Roo.form.Action.Submit = function(form, options){
7661 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7664 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7667 haveProgress : false,
7668 uploadComplete : false,
7670 // uploadProgress indicator.
7671 uploadProgress : function()
7673 if (!this.form.progressUrl) {
7677 if (!this.haveProgress) {
7678 Roo.MessageBox.progress("Uploading", "Uploading");
7680 if (this.uploadComplete) {
7681 Roo.MessageBox.hide();
7685 this.haveProgress = true;
7687 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7689 var c = new Roo.data.Connection();
7691 url : this.form.progressUrl,
7696 success : function(req){
7697 //console.log(data);
7701 rdata = Roo.decode(req.responseText)
7703 Roo.log("Invalid data from server..");
7707 if (!rdata || !rdata.success) {
7709 Roo.MessageBox.alert(Roo.encode(rdata));
7712 var data = rdata.data;
7714 if (this.uploadComplete) {
7715 Roo.MessageBox.hide();
7720 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7721 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7724 this.uploadProgress.defer(2000,this);
7727 failure: function(data) {
7728 Roo.log('progress url failed ');
7739 // run get Values on the form, so it syncs any secondary forms.
7740 this.form.getValues();
7742 var o = this.options;
7743 var method = this.getMethod();
7744 var isPost = method == 'POST';
7745 if(o.clientValidation === false || this.form.isValid()){
7747 if (this.form.progressUrl) {
7748 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7749 (new Date() * 1) + '' + Math.random());
7754 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7755 form:this.form.el.dom,
7756 url:this.getUrl(!isPost),
7758 params:isPost ? this.getParams() : null,
7759 isUpload: this.form.fileUpload
7762 this.uploadProgress();
7764 }else if (o.clientValidation !== false){ // client validation failed
7765 this.failureType = Roo.form.Action.CLIENT_INVALID;
7766 this.form.afterAction(this, false);
7770 success : function(response)
7772 this.uploadComplete= true;
7773 if (this.haveProgress) {
7774 Roo.MessageBox.hide();
7778 var result = this.processResponse(response);
7779 if(result === true || result.success){
7780 this.form.afterAction(this, true);
7784 this.form.markInvalid(result.errors);
7785 this.failureType = Roo.form.Action.SERVER_INVALID;
7787 this.form.afterAction(this, false);
7789 failure : function(response)
7791 this.uploadComplete= true;
7792 if (this.haveProgress) {
7793 Roo.MessageBox.hide();
7796 this.response = response;
7797 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7798 this.form.afterAction(this, false);
7801 handleResponse : function(response){
7802 if(this.form.errorReader){
7803 var rs = this.form.errorReader.read(response);
7806 for(var i = 0, len = rs.records.length; i < len; i++) {
7807 var r = rs.records[i];
7811 if(errors.length < 1){
7815 success : rs.success,
7821 ret = Roo.decode(response.responseText);
7825 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7835 Roo.form.Action.Load = function(form, options){
7836 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7837 this.reader = this.form.reader;
7840 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7845 Roo.Ajax.request(Roo.apply(
7846 this.createCallback(), {
7847 method:this.getMethod(),
7848 url:this.getUrl(false),
7849 params:this.getParams()
7853 success : function(response){
7855 var result = this.processResponse(response);
7856 if(result === true || !result.success || !result.data){
7857 this.failureType = Roo.form.Action.LOAD_FAILURE;
7858 this.form.afterAction(this, false);
7861 this.form.clearInvalid();
7862 this.form.setValues(result.data);
7863 this.form.afterAction(this, true);
7866 handleResponse : function(response){
7867 if(this.form.reader){
7868 var rs = this.form.reader.read(response);
7869 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7871 success : rs.success,
7875 return Roo.decode(response.responseText);
7879 Roo.form.Action.ACTION_TYPES = {
7880 'load' : Roo.form.Action.Load,
7881 'submit' : Roo.form.Action.Submit
7890 * @class Roo.bootstrap.Form
7891 * @extends Roo.bootstrap.Component
7892 * Bootstrap Form class
7893 * @cfg {String} method GET | POST (default POST)
7894 * @cfg {String} labelAlign top | left (default top)
7895 * @cfg {String} align left | right - for navbars
7896 * @cfg {Boolean} loadMask load mask when submit (default true)
7901 * @param {Object} config The config object
7905 Roo.bootstrap.Form = function(config){
7907 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7909 Roo.bootstrap.Form.popover.apply();
7913 * @event clientvalidation
7914 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7915 * @param {Form} this
7916 * @param {Boolean} valid true if the form has passed client-side validation
7918 clientvalidation: true,
7920 * @event beforeaction
7921 * Fires before any action is performed. Return false to cancel the action.
7922 * @param {Form} this
7923 * @param {Action} action The action to be performed
7927 * @event actionfailed
7928 * Fires when an action fails.
7929 * @param {Form} this
7930 * @param {Action} action The action that failed
7932 actionfailed : true,
7934 * @event actioncomplete
7935 * Fires when an action is completed.
7936 * @param {Form} this
7937 * @param {Action} action The action that completed
7939 actioncomplete : true
7943 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7946 * @cfg {String} method
7947 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7952 * The URL to use for form actions if one isn't supplied in the action options.
7955 * @cfg {Boolean} fileUpload
7956 * Set to true if this form is a file upload.
7960 * @cfg {Object} baseParams
7961 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7965 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7969 * @cfg {Sting} align (left|right) for navbar forms
7974 activeAction : null,
7977 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7978 * element by passing it or its id or mask the form itself by passing in true.
7981 waitMsgTarget : false,
7986 * @cfg {Boolean} errorMask (true|false) default false
7991 * @cfg {Number} maskOffset Default 100
7996 * @cfg {Boolean} maskBody
8000 getAutoCreate : function(){
8004 method : this.method || 'POST',
8005 id : this.id || Roo.id(),
8008 if (this.parent().xtype.match(/^Nav/)) {
8009 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8013 if (this.labelAlign == 'left' ) {
8014 cfg.cls += ' form-horizontal';
8020 initEvents : function()
8022 this.el.on('submit', this.onSubmit, this);
8023 // this was added as random key presses on the form where triggering form submit.
8024 this.el.on('keypress', function(e) {
8025 if (e.getCharCode() != 13) {
8028 // we might need to allow it for textareas.. and some other items.
8029 // check e.getTarget().
8031 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8035 Roo.log("keypress blocked");
8043 onSubmit : function(e){
8048 * Returns true if client-side validation on the form is successful.
8051 isValid : function(){
8052 var items = this.getItems();
8056 items.each(function(f){
8062 Roo.log('invalid field: ' + f.name);
8066 if(!target && f.el.isVisible(true)){
8072 if(this.errorMask && !valid){
8073 Roo.bootstrap.Form.popover.mask(this, target);
8080 * Returns true if any fields in this form have changed since their original load.
8083 isDirty : function(){
8085 var items = this.getItems();
8086 items.each(function(f){
8096 * Performs a predefined action (submit or load) or custom actions you define on this form.
8097 * @param {String} actionName The name of the action type
8098 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8099 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8100 * accept other config options):
8102 Property Type Description
8103 ---------------- --------------- ----------------------------------------------------------------------------------
8104 url String The url for the action (defaults to the form's url)
8105 method String The form method to use (defaults to the form's method, or POST if not defined)
8106 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8107 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8108 validate the form on the client (defaults to false)
8110 * @return {BasicForm} this
8112 doAction : function(action, options){
8113 if(typeof action == 'string'){
8114 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8116 if(this.fireEvent('beforeaction', this, action) !== false){
8117 this.beforeAction(action);
8118 action.run.defer(100, action);
8124 beforeAction : function(action){
8125 var o = action.options;
8130 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8132 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8135 // not really supported yet.. ??
8137 //if(this.waitMsgTarget === true){
8138 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8139 //}else if(this.waitMsgTarget){
8140 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8141 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8143 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8149 afterAction : function(action, success){
8150 this.activeAction = null;
8151 var o = action.options;
8156 Roo.get(document.body).unmask();
8162 //if(this.waitMsgTarget === true){
8163 // this.el.unmask();
8164 //}else if(this.waitMsgTarget){
8165 // this.waitMsgTarget.unmask();
8167 // Roo.MessageBox.updateProgress(1);
8168 // Roo.MessageBox.hide();
8175 Roo.callback(o.success, o.scope, [this, action]);
8176 this.fireEvent('actioncomplete', this, action);
8180 // failure condition..
8181 // we have a scenario where updates need confirming.
8182 // eg. if a locking scenario exists..
8183 // we look for { errors : { needs_confirm : true }} in the response.
8185 (typeof(action.result) != 'undefined') &&
8186 (typeof(action.result.errors) != 'undefined') &&
8187 (typeof(action.result.errors.needs_confirm) != 'undefined')
8190 Roo.log("not supported yet");
8193 Roo.MessageBox.confirm(
8194 "Change requires confirmation",
8195 action.result.errorMsg,
8200 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8210 Roo.callback(o.failure, o.scope, [this, action]);
8211 // show an error message if no failed handler is set..
8212 if (!this.hasListener('actionfailed')) {
8213 Roo.log("need to add dialog support");
8215 Roo.MessageBox.alert("Error",
8216 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8217 action.result.errorMsg :
8218 "Saving Failed, please check your entries or try again"
8223 this.fireEvent('actionfailed', this, action);
8228 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8229 * @param {String} id The value to search for
8232 findField : function(id){
8233 var items = this.getItems();
8234 var field = items.get(id);
8236 items.each(function(f){
8237 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8244 return field || null;
8247 * Mark fields in this form invalid in bulk.
8248 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8249 * @return {BasicForm} this
8251 markInvalid : function(errors){
8252 if(errors instanceof Array){
8253 for(var i = 0, len = errors.length; i < len; i++){
8254 var fieldError = errors[i];
8255 var f = this.findField(fieldError.id);
8257 f.markInvalid(fieldError.msg);
8263 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8264 field.markInvalid(errors[id]);
8268 //Roo.each(this.childForms || [], function (f) {
8269 // f.markInvalid(errors);
8276 * Set values for fields in this form in bulk.
8277 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8278 * @return {BasicForm} this
8280 setValues : function(values){
8281 if(values instanceof Array){ // array of objects
8282 for(var i = 0, len = values.length; i < len; i++){
8284 var f = this.findField(v.id);
8286 f.setValue(v.value);
8287 if(this.trackResetOnLoad){
8288 f.originalValue = f.getValue();
8292 }else{ // object hash
8295 if(typeof values[id] != 'function' && (field = this.findField(id))){
8297 if (field.setFromData &&
8299 field.displayField &&
8300 // combos' with local stores can
8301 // be queried via setValue()
8302 // to set their value..
8303 (field.store && !field.store.isLocal)
8307 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8308 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8309 field.setFromData(sd);
8311 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8313 field.setFromData(values);
8316 field.setValue(values[id]);
8320 if(this.trackResetOnLoad){
8321 field.originalValue = field.getValue();
8327 //Roo.each(this.childForms || [], function (f) {
8328 // f.setValues(values);
8335 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8336 * they are returned as an array.
8337 * @param {Boolean} asString
8340 getValues : function(asString){
8341 //if (this.childForms) {
8342 // copy values from the child forms
8343 // Roo.each(this.childForms, function (f) {
8344 // this.setValues(f.getValues());
8350 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8351 if(asString === true){
8354 return Roo.urlDecode(fs);
8358 * Returns the fields in this form as an object with key/value pairs.
8359 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8362 getFieldValues : function(with_hidden)
8364 var items = this.getItems();
8366 items.each(function(f){
8372 var v = f.getValue();
8374 if (f.inputType =='radio') {
8375 if (typeof(ret[f.getName()]) == 'undefined') {
8376 ret[f.getName()] = ''; // empty..
8379 if (!f.el.dom.checked) {
8387 if(f.xtype == 'MoneyField'){
8388 ret[f.currencyName] = f.getCurrency();
8391 // not sure if this supported any more..
8392 if ((typeof(v) == 'object') && f.getRawValue) {
8393 v = f.getRawValue() ; // dates..
8395 // combo boxes where name != hiddenName...
8396 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8397 ret[f.name] = f.getRawValue();
8399 ret[f.getName()] = v;
8406 * Clears all invalid messages in this form.
8407 * @return {BasicForm} this
8409 clearInvalid : function(){
8410 var items = this.getItems();
8412 items.each(function(f){
8421 * @return {BasicForm} this
8424 var items = this.getItems();
8425 items.each(function(f){
8429 Roo.each(this.childForms || [], function (f) {
8437 getItems : function()
8439 var r=new Roo.util.MixedCollection(false, function(o){
8440 return o.id || (o.id = Roo.id());
8442 var iter = function(el) {
8449 Roo.each(el.items,function(e) {
8458 hideFields : function(items)
8460 Roo.each(items, function(i){
8462 var f = this.findField(i);
8473 showFields : function(items)
8475 Roo.each(items, function(i){
8477 var f = this.findField(i);
8490 Roo.apply(Roo.bootstrap.Form, {
8517 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8518 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8519 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8520 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8523 this.maskEl.top.enableDisplayMode("block");
8524 this.maskEl.left.enableDisplayMode("block");
8525 this.maskEl.bottom.enableDisplayMode("block");
8526 this.maskEl.right.enableDisplayMode("block");
8528 this.toolTip = new Roo.bootstrap.Tooltip({
8529 cls : 'roo-form-error-popover',
8531 'left' : ['r-l', [-2,0], 'right'],
8532 'right' : ['l-r', [2,0], 'left'],
8533 'bottom' : ['tl-bl', [0,2], 'top'],
8534 'top' : [ 'bl-tl', [0,-2], 'bottom']
8538 this.toolTip.render(Roo.get(document.body));
8540 this.toolTip.el.enableDisplayMode("block");
8542 Roo.get(document.body).on('click', function(){
8546 Roo.get(document.body).on('touchstart', function(){
8550 this.isApplied = true
8553 mask : function(form, target)
8557 this.target = target;
8559 if(!this.form.errorMask || !target.el){
8563 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8565 Roo.log(scrollable);
8567 var ot = this.target.el.calcOffsetsTo(scrollable);
8569 var scrollTo = ot[1] - this.form.maskOffset;
8571 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8573 scrollable.scrollTo('top', scrollTo);
8575 var box = this.target.el.getBox();
8577 var zIndex = Roo.bootstrap.Modal.zIndex++;
8580 this.maskEl.top.setStyle('position', 'absolute');
8581 this.maskEl.top.setStyle('z-index', zIndex);
8582 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8583 this.maskEl.top.setLeft(0);
8584 this.maskEl.top.setTop(0);
8585 this.maskEl.top.show();
8587 this.maskEl.left.setStyle('position', 'absolute');
8588 this.maskEl.left.setStyle('z-index', zIndex);
8589 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8590 this.maskEl.left.setLeft(0);
8591 this.maskEl.left.setTop(box.y - this.padding);
8592 this.maskEl.left.show();
8594 this.maskEl.bottom.setStyle('position', 'absolute');
8595 this.maskEl.bottom.setStyle('z-index', zIndex);
8596 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8597 this.maskEl.bottom.setLeft(0);
8598 this.maskEl.bottom.setTop(box.bottom + this.padding);
8599 this.maskEl.bottom.show();
8601 this.maskEl.right.setStyle('position', 'absolute');
8602 this.maskEl.right.setStyle('z-index', zIndex);
8603 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8604 this.maskEl.right.setLeft(box.right + this.padding);
8605 this.maskEl.right.setTop(box.y - this.padding);
8606 this.maskEl.right.show();
8608 this.toolTip.bindEl = this.target.el;
8610 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8612 var tip = this.target.blankText;
8614 if(this.target.getValue() !== '' ) {
8616 if (this.target.invalidText.length) {
8617 tip = this.target.invalidText;
8618 } else if (this.target.regexText.length){
8619 tip = this.target.regexText;
8623 this.toolTip.show(tip);
8625 this.intervalID = window.setInterval(function() {
8626 Roo.bootstrap.Form.popover.unmask();
8629 window.onwheel = function(){ return false;};
8631 (function(){ this.isMasked = true; }).defer(500, this);
8637 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8641 this.maskEl.top.setStyle('position', 'absolute');
8642 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8643 this.maskEl.top.hide();
8645 this.maskEl.left.setStyle('position', 'absolute');
8646 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8647 this.maskEl.left.hide();
8649 this.maskEl.bottom.setStyle('position', 'absolute');
8650 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8651 this.maskEl.bottom.hide();
8653 this.maskEl.right.setStyle('position', 'absolute');
8654 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8655 this.maskEl.right.hide();
8657 this.toolTip.hide();
8659 this.toolTip.el.hide();
8661 window.onwheel = function(){ return true;};
8663 if(this.intervalID){
8664 window.clearInterval(this.intervalID);
8665 this.intervalID = false;
8668 this.isMasked = false;
8678 * Ext JS Library 1.1.1
8679 * Copyright(c) 2006-2007, Ext JS, LLC.
8681 * Originally Released Under LGPL - original licence link has changed is not relivant.
8684 * <script type="text/javascript">
8687 * @class Roo.form.VTypes
8688 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8691 Roo.form.VTypes = function(){
8692 // closure these in so they are only created once.
8693 var alpha = /^[a-zA-Z_]+$/;
8694 var alphanum = /^[a-zA-Z0-9_]+$/;
8695 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8696 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8698 // All these messages and functions are configurable
8701 * The function used to validate email addresses
8702 * @param {String} value The email address
8704 'email' : function(v){
8705 return email.test(v);
8708 * The error text to display when the email validation function returns false
8711 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8713 * The keystroke filter mask to be applied on email input
8716 'emailMask' : /[a-z0-9_\.\-@]/i,
8719 * The function used to validate URLs
8720 * @param {String} value The URL
8722 'url' : function(v){
8726 * The error text to display when the url validation function returns false
8729 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8732 * The function used to validate alpha values
8733 * @param {String} value The value
8735 'alpha' : function(v){
8736 return alpha.test(v);
8739 * The error text to display when the alpha validation function returns false
8742 'alphaText' : 'This field should only contain letters and _',
8744 * The keystroke filter mask to be applied on alpha input
8747 'alphaMask' : /[a-z_]/i,
8750 * The function used to validate alphanumeric values
8751 * @param {String} value The value
8753 'alphanum' : function(v){
8754 return alphanum.test(v);
8757 * The error text to display when the alphanumeric validation function returns false
8760 'alphanumText' : 'This field should only contain letters, numbers and _',
8762 * The keystroke filter mask to be applied on alphanumeric input
8765 'alphanumMask' : /[a-z0-9_]/i
8775 * @class Roo.bootstrap.Input
8776 * @extends Roo.bootstrap.Component
8777 * Bootstrap Input class
8778 * @cfg {Boolean} disabled is it disabled
8779 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8780 * @cfg {String} name name of the input
8781 * @cfg {string} fieldLabel - the label associated
8782 * @cfg {string} placeholder - placeholder to put in text.
8783 * @cfg {string} before - input group add on before
8784 * @cfg {string} after - input group add on after
8785 * @cfg {string} size - (lg|sm) or leave empty..
8786 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8787 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8788 * @cfg {Number} md colspan out of 12 for computer-sized screens
8789 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8790 * @cfg {string} value default value of the input
8791 * @cfg {Number} labelWidth set the width of label
8792 * @cfg {Number} labellg set the width of label (1-12)
8793 * @cfg {Number} labelmd set the width of label (1-12)
8794 * @cfg {Number} labelsm set the width of label (1-12)
8795 * @cfg {Number} labelxs set the width of label (1-12)
8796 * @cfg {String} labelAlign (top|left)
8797 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8798 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8799 * @cfg {String} indicatorpos (left|right) default left
8800 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8801 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8803 * @cfg {String} align (left|center|right) Default left
8804 * @cfg {Boolean} forceFeedback (true|false) Default false
8807 * Create a new Input
8808 * @param {Object} config The config object
8811 Roo.bootstrap.Input = function(config){
8813 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8818 * Fires when this field receives input focus.
8819 * @param {Roo.form.Field} this
8824 * Fires when this field loses input focus.
8825 * @param {Roo.form.Field} this
8830 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8831 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8832 * @param {Roo.form.Field} this
8833 * @param {Roo.EventObject} e The event object
8838 * Fires just before the field blurs if the field value has changed.
8839 * @param {Roo.form.Field} this
8840 * @param {Mixed} newValue The new value
8841 * @param {Mixed} oldValue The original value
8846 * Fires after the field has been marked as invalid.
8847 * @param {Roo.form.Field} this
8848 * @param {String} msg The validation message
8853 * Fires after the field has been validated with no errors.
8854 * @param {Roo.form.Field} this
8859 * Fires after the key up
8860 * @param {Roo.form.Field} this
8861 * @param {Roo.EventObject} e The event Object
8867 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8869 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8870 automatic validation (defaults to "keyup").
8872 validationEvent : "keyup",
8874 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8876 validateOnBlur : true,
8878 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8880 validationDelay : 250,
8882 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8884 focusClass : "x-form-focus", // not needed???
8888 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8890 invalidClass : "has-warning",
8893 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8895 validClass : "has-success",
8898 * @cfg {Boolean} hasFeedback (true|false) default true
8903 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8905 invalidFeedbackClass : "glyphicon-warning-sign",
8908 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8910 validFeedbackClass : "glyphicon-ok",
8913 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8915 selectOnFocus : false,
8918 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8922 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8927 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8929 disableKeyFilter : false,
8932 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8936 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8940 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8942 blankText : "Please complete this mandatory field",
8945 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8949 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8951 maxLength : Number.MAX_VALUE,
8953 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8955 minLengthText : "The minimum length for this field is {0}",
8957 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8959 maxLengthText : "The maximum length for this field is {0}",
8963 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8964 * If available, this function will be called only after the basic validators all return true, and will be passed the
8965 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8969 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8970 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8971 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8975 * @cfg {String} regexText -- Depricated - use Invalid Text
8980 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8986 autocomplete: false,
9005 formatedValue : false,
9006 forceFeedback : false,
9008 indicatorpos : 'left',
9018 parentLabelAlign : function()
9021 while (parent.parent()) {
9022 parent = parent.parent();
9023 if (typeof(parent.labelAlign) !='undefined') {
9024 return parent.labelAlign;
9031 getAutoCreate : function()
9033 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9039 if(this.inputType != 'hidden'){
9040 cfg.cls = 'form-group' //input-group
9046 type : this.inputType,
9048 cls : 'form-control',
9049 placeholder : this.placeholder || '',
9050 autocomplete : this.autocomplete || 'new-password'
9053 if(this.capture.length){
9054 input.capture = this.capture;
9057 if(this.accept.length){
9058 input.accept = this.accept + "/*";
9062 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9065 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9066 input.maxLength = this.maxLength;
9069 if (this.disabled) {
9070 input.disabled=true;
9073 if (this.readOnly) {
9074 input.readonly=true;
9078 input.name = this.name;
9082 input.cls += ' input-' + this.size;
9086 ['xs','sm','md','lg'].map(function(size){
9087 if (settings[size]) {
9088 cfg.cls += ' col-' + size + '-' + settings[size];
9092 var inputblock = input;
9096 cls: 'glyphicon form-control-feedback'
9099 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9102 cls : 'has-feedback',
9110 if (this.before || this.after) {
9113 cls : 'input-group',
9117 if (this.before && typeof(this.before) == 'string') {
9119 inputblock.cn.push({
9121 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9125 if (this.before && typeof(this.before) == 'object') {
9126 this.before = Roo.factory(this.before);
9128 inputblock.cn.push({
9130 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9131 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9135 inputblock.cn.push(input);
9137 if (this.after && typeof(this.after) == 'string') {
9138 inputblock.cn.push({
9140 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9144 if (this.after && typeof(this.after) == 'object') {
9145 this.after = Roo.factory(this.after);
9147 inputblock.cn.push({
9149 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9150 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9154 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9155 inputblock.cls += ' has-feedback';
9156 inputblock.cn.push(feedback);
9161 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9162 tooltip : 'This field is required'
9164 if (Roo.bootstrap.version == 4) {
9167 style : 'display-none'
9170 if (align ==='left' && this.fieldLabel.length) {
9172 cfg.cls += ' roo-form-group-label-left row';
9179 cls : 'control-label col-form-label',
9180 html : this.fieldLabel
9191 var labelCfg = cfg.cn[1];
9192 var contentCfg = cfg.cn[2];
9194 if(this.indicatorpos == 'right'){
9199 cls : 'control-label col-form-label',
9203 html : this.fieldLabel
9217 labelCfg = cfg.cn[0];
9218 contentCfg = cfg.cn[1];
9222 if(this.labelWidth > 12){
9223 labelCfg.style = "width: " + this.labelWidth + 'px';
9226 if(this.labelWidth < 13 && this.labelmd == 0){
9227 this.labelmd = this.labelWidth;
9230 if(this.labellg > 0){
9231 labelCfg.cls += ' col-lg-' + this.labellg;
9232 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9235 if(this.labelmd > 0){
9236 labelCfg.cls += ' col-md-' + this.labelmd;
9237 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9240 if(this.labelsm > 0){
9241 labelCfg.cls += ' col-sm-' + this.labelsm;
9242 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9245 if(this.labelxs > 0){
9246 labelCfg.cls += ' col-xs-' + this.labelxs;
9247 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9251 } else if ( this.fieldLabel.length) {
9256 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9257 tooltip : 'This field is required'
9261 //cls : 'input-group-addon',
9262 html : this.fieldLabel
9270 if(this.indicatorpos == 'right'){
9275 //cls : 'input-group-addon',
9276 html : this.fieldLabel
9281 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9282 tooltip : 'This field is required'
9302 if (this.parentType === 'Navbar' && this.parent().bar) {
9303 cfg.cls += ' navbar-form';
9306 if (this.parentType === 'NavGroup') {
9307 cfg.cls += ' navbar-form';
9315 * return the real input element.
9317 inputEl: function ()
9319 return this.el.select('input.form-control',true).first();
9322 tooltipEl : function()
9324 return this.inputEl();
9327 indicatorEl : function()
9329 if (Roo.bootstrap.version == 4) {
9330 return false; // not enabled in v4 yet.
9333 var indicator = this.el.select('i.roo-required-indicator',true).first();
9343 setDisabled : function(v)
9345 var i = this.inputEl().dom;
9347 i.removeAttribute('disabled');
9351 i.setAttribute('disabled','true');
9353 initEvents : function()
9356 this.inputEl().on("keydown" , this.fireKey, this);
9357 this.inputEl().on("focus", this.onFocus, this);
9358 this.inputEl().on("blur", this.onBlur, this);
9360 this.inputEl().relayEvent('keyup', this);
9362 this.indicator = this.indicatorEl();
9365 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9368 // reference to original value for reset
9369 this.originalValue = this.getValue();
9370 //Roo.form.TextField.superclass.initEvents.call(this);
9371 if(this.validationEvent == 'keyup'){
9372 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9373 this.inputEl().on('keyup', this.filterValidation, this);
9375 else if(this.validationEvent !== false){
9376 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9379 if(this.selectOnFocus){
9380 this.on("focus", this.preFocus, this);
9383 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9384 this.inputEl().on("keypress", this.filterKeys, this);
9386 this.inputEl().relayEvent('keypress', this);
9389 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9390 this.el.on("click", this.autoSize, this);
9393 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9394 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9397 if (typeof(this.before) == 'object') {
9398 this.before.render(this.el.select('.roo-input-before',true).first());
9400 if (typeof(this.after) == 'object') {
9401 this.after.render(this.el.select('.roo-input-after',true).first());
9404 this.inputEl().on('change', this.onChange, this);
9407 filterValidation : function(e){
9408 if(!e.isNavKeyPress()){
9409 this.validationTask.delay(this.validationDelay);
9413 * Validates the field value
9414 * @return {Boolean} True if the value is valid, else false
9416 validate : function(){
9417 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9418 if(this.disabled || this.validateValue(this.getRawValue())){
9429 * Validates a value according to the field's validation rules and marks the field as invalid
9430 * if the validation fails
9431 * @param {Mixed} value The value to validate
9432 * @return {Boolean} True if the value is valid, else false
9434 validateValue : function(value)
9436 if(this.getVisibilityEl().hasClass('hidden')){
9440 if(value.length < 1) { // if it's blank
9441 if(this.allowBlank){
9447 if(value.length < this.minLength){
9450 if(value.length > this.maxLength){
9454 var vt = Roo.form.VTypes;
9455 if(!vt[this.vtype](value, this)){
9459 if(typeof this.validator == "function"){
9460 var msg = this.validator(value);
9464 if (typeof(msg) == 'string') {
9465 this.invalidText = msg;
9469 if(this.regex && !this.regex.test(value)){
9477 fireKey : function(e){
9478 //Roo.log('field ' + e.getKey());
9479 if(e.isNavKeyPress()){
9480 this.fireEvent("specialkey", this, e);
9483 focus : function (selectText){
9485 this.inputEl().focus();
9486 if(selectText === true){
9487 this.inputEl().dom.select();
9493 onFocus : function(){
9494 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9495 // this.el.addClass(this.focusClass);
9498 this.hasFocus = true;
9499 this.startValue = this.getValue();
9500 this.fireEvent("focus", this);
9504 beforeBlur : Roo.emptyFn,
9508 onBlur : function(){
9510 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9511 //this.el.removeClass(this.focusClass);
9513 this.hasFocus = false;
9514 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9517 var v = this.getValue();
9518 if(String(v) !== String(this.startValue)){
9519 this.fireEvent('change', this, v, this.startValue);
9521 this.fireEvent("blur", this);
9524 onChange : function(e)
9526 var v = this.getValue();
9527 if(String(v) !== String(this.startValue)){
9528 this.fireEvent('change', this, v, this.startValue);
9534 * Resets the current field value to the originally loaded value and clears any validation messages
9537 this.setValue(this.originalValue);
9541 * Returns the name of the field
9542 * @return {Mixed} name The name field
9544 getName: function(){
9548 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9549 * @return {Mixed} value The field value
9551 getValue : function(){
9553 var v = this.inputEl().getValue();
9558 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9559 * @return {Mixed} value The field value
9561 getRawValue : function(){
9562 var v = this.inputEl().getValue();
9568 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9569 * @param {Mixed} value The value to set
9571 setRawValue : function(v){
9572 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9575 selectText : function(start, end){
9576 var v = this.getRawValue();
9578 start = start === undefined ? 0 : start;
9579 end = end === undefined ? v.length : end;
9580 var d = this.inputEl().dom;
9581 if(d.setSelectionRange){
9582 d.setSelectionRange(start, end);
9583 }else if(d.createTextRange){
9584 var range = d.createTextRange();
9585 range.moveStart("character", start);
9586 range.moveEnd("character", v.length-end);
9593 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9594 * @param {Mixed} value The value to set
9596 setValue : function(v){
9599 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9605 processValue : function(value){
9606 if(this.stripCharsRe){
9607 var newValue = value.replace(this.stripCharsRe, '');
9608 if(newValue !== value){
9609 this.setRawValue(newValue);
9616 preFocus : function(){
9618 if(this.selectOnFocus){
9619 this.inputEl().dom.select();
9622 filterKeys : function(e){
9624 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9627 var c = e.getCharCode(), cc = String.fromCharCode(c);
9628 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9631 if(!this.maskRe.test(cc)){
9636 * Clear any invalid styles/messages for this field
9638 clearInvalid : function(){
9640 if(!this.el || this.preventMark){ // not rendered
9645 this.el.removeClass(this.invalidClass);
9647 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9649 var feedback = this.el.select('.form-control-feedback', true).first();
9652 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9658 this.indicator.removeClass('visible');
9659 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9662 this.fireEvent('valid', this);
9666 * Mark this field as valid
9668 markValid : function()
9670 if(!this.el || this.preventMark){ // not rendered...
9674 this.el.removeClass([this.invalidClass, this.validClass]);
9676 var feedback = this.el.select('.form-control-feedback', true).first();
9679 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9683 this.indicator.removeClass('visible');
9684 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9691 if(this.allowBlank && !this.getRawValue().length){
9695 this.el.addClass(this.validClass);
9697 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9699 var feedback = this.el.select('.form-control-feedback', true).first();
9702 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9703 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9708 this.fireEvent('valid', this);
9712 * Mark this field as invalid
9713 * @param {String} msg The validation message
9715 markInvalid : function(msg)
9717 if(!this.el || this.preventMark){ // not rendered
9721 this.el.removeClass([this.invalidClass, this.validClass]);
9723 var feedback = this.el.select('.form-control-feedback', true).first();
9726 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9733 if(this.allowBlank && !this.getRawValue().length){
9738 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9739 this.indicator.addClass('visible');
9742 this.el.addClass(this.invalidClass);
9744 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9746 var feedback = this.el.select('.form-control-feedback', true).first();
9749 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9751 if(this.getValue().length || this.forceFeedback){
9752 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9759 this.fireEvent('invalid', this, msg);
9762 SafariOnKeyDown : function(event)
9764 // this is a workaround for a password hang bug on chrome/ webkit.
9765 if (this.inputEl().dom.type != 'password') {
9769 var isSelectAll = false;
9771 if(this.inputEl().dom.selectionEnd > 0){
9772 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9774 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9775 event.preventDefault();
9780 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9782 event.preventDefault();
9783 // this is very hacky as keydown always get's upper case.
9785 var cc = String.fromCharCode(event.getCharCode());
9786 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9790 adjustWidth : function(tag, w){
9791 tag = tag.toLowerCase();
9792 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9793 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9797 if(tag == 'textarea'){
9800 }else if(Roo.isOpera){
9804 if(tag == 'textarea'){
9812 setFieldLabel : function(v)
9818 if(this.indicatorEl()){
9819 var ar = this.el.select('label > span',true);
9821 if (ar.elements.length) {
9822 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9823 this.fieldLabel = v;
9827 var br = this.el.select('label',true);
9829 if(br.elements.length) {
9830 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9831 this.fieldLabel = v;
9835 Roo.log('Cannot Found any of label > span || label in input');
9839 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9840 this.fieldLabel = v;
9855 * @class Roo.bootstrap.TextArea
9856 * @extends Roo.bootstrap.Input
9857 * Bootstrap TextArea class
9858 * @cfg {Number} cols Specifies the visible width of a text area
9859 * @cfg {Number} rows Specifies the visible number of lines in a text area
9860 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9861 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9862 * @cfg {string} html text
9865 * Create a new TextArea
9866 * @param {Object} config The config object
9869 Roo.bootstrap.TextArea = function(config){
9870 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9874 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9884 getAutoCreate : function(){
9886 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9892 if(this.inputType != 'hidden'){
9893 cfg.cls = 'form-group' //input-group
9901 value : this.value || '',
9902 html: this.html || '',
9903 cls : 'form-control',
9904 placeholder : this.placeholder || ''
9908 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9909 input.maxLength = this.maxLength;
9913 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9917 input.cols = this.cols;
9920 if (this.readOnly) {
9921 input.readonly = true;
9925 input.name = this.name;
9929 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9933 ['xs','sm','md','lg'].map(function(size){
9934 if (settings[size]) {
9935 cfg.cls += ' col-' + size + '-' + settings[size];
9939 var inputblock = input;
9941 if(this.hasFeedback && !this.allowBlank){
9945 cls: 'glyphicon form-control-feedback'
9949 cls : 'has-feedback',
9958 if (this.before || this.after) {
9961 cls : 'input-group',
9965 inputblock.cn.push({
9967 cls : 'input-group-addon',
9972 inputblock.cn.push(input);
9974 if(this.hasFeedback && !this.allowBlank){
9975 inputblock.cls += ' has-feedback';
9976 inputblock.cn.push(feedback);
9980 inputblock.cn.push({
9982 cls : 'input-group-addon',
9989 if (align ==='left' && this.fieldLabel.length) {
9994 cls : 'control-label',
9995 html : this.fieldLabel
10006 if(this.labelWidth > 12){
10007 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10010 if(this.labelWidth < 13 && this.labelmd == 0){
10011 this.labelmd = this.labelWidth;
10014 if(this.labellg > 0){
10015 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10016 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10019 if(this.labelmd > 0){
10020 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10021 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10024 if(this.labelsm > 0){
10025 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10026 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10029 if(this.labelxs > 0){
10030 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10031 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10034 } else if ( this.fieldLabel.length) {
10039 //cls : 'input-group-addon',
10040 html : this.fieldLabel
10058 if (this.disabled) {
10059 input.disabled=true;
10066 * return the real textarea element.
10068 inputEl: function ()
10070 return this.el.select('textarea.form-control',true).first();
10074 * Clear any invalid styles/messages for this field
10076 clearInvalid : function()
10079 if(!this.el || this.preventMark){ // not rendered
10083 var label = this.el.select('label', true).first();
10084 var icon = this.el.select('i.fa-star', true).first();
10090 this.el.removeClass(this.invalidClass);
10092 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10094 var feedback = this.el.select('.form-control-feedback', true).first();
10097 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10102 this.fireEvent('valid', this);
10106 * Mark this field as valid
10108 markValid : function()
10110 if(!this.el || this.preventMark){ // not rendered
10114 this.el.removeClass([this.invalidClass, this.validClass]);
10116 var feedback = this.el.select('.form-control-feedback', true).first();
10119 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10122 if(this.disabled || this.allowBlank){
10126 var label = this.el.select('label', true).first();
10127 var icon = this.el.select('i.fa-star', true).first();
10133 this.el.addClass(this.validClass);
10135 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10137 var feedback = this.el.select('.form-control-feedback', true).first();
10140 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10141 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10146 this.fireEvent('valid', this);
10150 * Mark this field as invalid
10151 * @param {String} msg The validation message
10153 markInvalid : function(msg)
10155 if(!this.el || this.preventMark){ // not rendered
10159 this.el.removeClass([this.invalidClass, this.validClass]);
10161 var feedback = this.el.select('.form-control-feedback', true).first();
10164 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10167 if(this.disabled || this.allowBlank){
10171 var label = this.el.select('label', true).first();
10172 var icon = this.el.select('i.fa-star', true).first();
10174 if(!this.getValue().length && label && !icon){
10175 this.el.createChild({
10177 cls : 'text-danger fa fa-lg fa-star',
10178 tooltip : 'This field is required',
10179 style : 'margin-right:5px;'
10183 this.el.addClass(this.invalidClass);
10185 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10187 var feedback = this.el.select('.form-control-feedback', true).first();
10190 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10192 if(this.getValue().length || this.forceFeedback){
10193 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10200 this.fireEvent('invalid', this, msg);
10208 * trigger field - base class for combo..
10213 * @class Roo.bootstrap.TriggerField
10214 * @extends Roo.bootstrap.Input
10215 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10216 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10217 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10218 * for which you can provide a custom implementation. For example:
10220 var trigger = new Roo.bootstrap.TriggerField();
10221 trigger.onTriggerClick = myTriggerFn;
10222 trigger.applyTo('my-field');
10225 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10226 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10227 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10228 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10229 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10232 * Create a new TriggerField.
10233 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10234 * to the base TextField)
10236 Roo.bootstrap.TriggerField = function(config){
10237 this.mimicing = false;
10238 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10241 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10243 * @cfg {String} triggerClass A CSS class to apply to the trigger
10246 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10251 * @cfg {Boolean} removable (true|false) special filter default false
10255 /** @cfg {Boolean} grow @hide */
10256 /** @cfg {Number} growMin @hide */
10257 /** @cfg {Number} growMax @hide */
10263 autoSize: Roo.emptyFn,
10267 deferHeight : true,
10270 actionMode : 'wrap',
10275 getAutoCreate : function(){
10277 var align = this.labelAlign || this.parentLabelAlign();
10282 cls: 'form-group' //input-group
10289 type : this.inputType,
10290 cls : 'form-control',
10291 autocomplete: 'new-password',
10292 placeholder : this.placeholder || ''
10296 input.name = this.name;
10299 input.cls += ' input-' + this.size;
10302 if (this.disabled) {
10303 input.disabled=true;
10306 var inputblock = input;
10308 if(this.hasFeedback && !this.allowBlank){
10312 cls: 'glyphicon form-control-feedback'
10315 if(this.removable && !this.editable && !this.tickable){
10317 cls : 'has-feedback',
10323 cls : 'roo-combo-removable-btn close'
10330 cls : 'has-feedback',
10339 if(this.removable && !this.editable && !this.tickable){
10341 cls : 'roo-removable',
10347 cls : 'roo-combo-removable-btn close'
10354 if (this.before || this.after) {
10357 cls : 'input-group',
10361 inputblock.cn.push({
10363 cls : 'input-group-addon input-group-prepend input-group-text',
10368 inputblock.cn.push(input);
10370 if(this.hasFeedback && !this.allowBlank){
10371 inputblock.cls += ' has-feedback';
10372 inputblock.cn.push(feedback);
10376 inputblock.cn.push({
10378 cls : 'input-group-addon input-group-append input-group-text',
10391 cls: 'form-hidden-field'
10398 var ibwrap = inputbox;
10403 cls: 'roo-select2-choices',
10407 cls: 'roo-select2-search-field',
10419 cls: 'roo-select2-container input-group',
10424 cls: 'form-hidden-field'
10430 if(!this.multiple && this.showToggleBtn){
10436 if (this.caret != false) {
10439 cls: 'fa fa-' + this.caret
10446 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10451 cls: 'combobox-clear',
10465 combobox.cls += ' roo-select2-container-multi';
10469 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10470 tooltip : 'This field is required'
10472 if (Roo.bootstrap.version == 4) {
10475 style : 'display:none'
10480 if (align ==='left' && this.fieldLabel.length) {
10482 cfg.cls += ' roo-form-group-label-left row';
10489 cls : 'control-label',
10490 html : this.fieldLabel
10502 var labelCfg = cfg.cn[1];
10503 var contentCfg = cfg.cn[2];
10505 if(this.indicatorpos == 'right'){
10510 cls : 'control-label',
10514 html : this.fieldLabel
10528 labelCfg = cfg.cn[0];
10529 contentCfg = cfg.cn[1];
10532 if(this.labelWidth > 12){
10533 labelCfg.style = "width: " + this.labelWidth + 'px';
10536 if(this.labelWidth < 13 && this.labelmd == 0){
10537 this.labelmd = this.labelWidth;
10540 if(this.labellg > 0){
10541 labelCfg.cls += ' col-lg-' + this.labellg;
10542 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10545 if(this.labelmd > 0){
10546 labelCfg.cls += ' col-md-' + this.labelmd;
10547 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10550 if(this.labelsm > 0){
10551 labelCfg.cls += ' col-sm-' + this.labelsm;
10552 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10555 if(this.labelxs > 0){
10556 labelCfg.cls += ' col-xs-' + this.labelxs;
10557 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10560 } else if ( this.fieldLabel.length) {
10561 // Roo.log(" label");
10566 //cls : 'input-group-addon',
10567 html : this.fieldLabel
10575 if(this.indicatorpos == 'right'){
10583 html : this.fieldLabel
10597 // Roo.log(" no label && no align");
10604 ['xs','sm','md','lg'].map(function(size){
10605 if (settings[size]) {
10606 cfg.cls += ' col-' + size + '-' + settings[size];
10617 onResize : function(w, h){
10618 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10619 // if(typeof w == 'number'){
10620 // var x = w - this.trigger.getWidth();
10621 // this.inputEl().setWidth(this.adjustWidth('input', x));
10622 // this.trigger.setStyle('left', x+'px');
10627 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10630 getResizeEl : function(){
10631 return this.inputEl();
10635 getPositionEl : function(){
10636 return this.inputEl();
10640 alignErrorIcon : function(){
10641 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10645 initEvents : function(){
10649 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10650 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10651 if(!this.multiple && this.showToggleBtn){
10652 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10653 if(this.hideTrigger){
10654 this.trigger.setDisplayed(false);
10656 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10660 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10663 if(this.removable && !this.editable && !this.tickable){
10664 var close = this.closeTriggerEl();
10667 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10668 close.on('click', this.removeBtnClick, this, close);
10672 //this.trigger.addClassOnOver('x-form-trigger-over');
10673 //this.trigger.addClassOnClick('x-form-trigger-click');
10676 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10680 closeTriggerEl : function()
10682 var close = this.el.select('.roo-combo-removable-btn', true).first();
10683 return close ? close : false;
10686 removeBtnClick : function(e, h, el)
10688 e.preventDefault();
10690 if(this.fireEvent("remove", this) !== false){
10692 this.fireEvent("afterremove", this)
10696 createList : function()
10698 this.list = Roo.get(document.body).createChild({
10700 cls: 'typeahead typeahead-long dropdown-menu',
10701 style: 'display:none'
10704 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10709 initTrigger : function(){
10714 onDestroy : function(){
10716 this.trigger.removeAllListeners();
10717 // this.trigger.remove();
10720 // this.wrap.remove();
10722 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10726 onFocus : function(){
10727 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10729 if(!this.mimicing){
10730 this.wrap.addClass('x-trigger-wrap-focus');
10731 this.mimicing = true;
10732 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10733 if(this.monitorTab){
10734 this.el.on("keydown", this.checkTab, this);
10741 checkTab : function(e){
10742 if(e.getKey() == e.TAB){
10743 this.triggerBlur();
10748 onBlur : function(){
10753 mimicBlur : function(e, t){
10755 if(!this.wrap.contains(t) && this.validateBlur()){
10756 this.triggerBlur();
10762 triggerBlur : function(){
10763 this.mimicing = false;
10764 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10765 if(this.monitorTab){
10766 this.el.un("keydown", this.checkTab, this);
10768 //this.wrap.removeClass('x-trigger-wrap-focus');
10769 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10773 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10774 validateBlur : function(e, t){
10779 onDisable : function(){
10780 this.inputEl().dom.disabled = true;
10781 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10783 // this.wrap.addClass('x-item-disabled');
10788 onEnable : function(){
10789 this.inputEl().dom.disabled = false;
10790 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10792 // this.el.removeClass('x-item-disabled');
10797 onShow : function(){
10798 var ae = this.getActionEl();
10801 ae.dom.style.display = '';
10802 ae.dom.style.visibility = 'visible';
10808 onHide : function(){
10809 var ae = this.getActionEl();
10810 ae.dom.style.display = 'none';
10814 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10815 * by an implementing function.
10817 * @param {EventObject} e
10819 onTriggerClick : Roo.emptyFn
10823 * Ext JS Library 1.1.1
10824 * Copyright(c) 2006-2007, Ext JS, LLC.
10826 * Originally Released Under LGPL - original licence link has changed is not relivant.
10829 * <script type="text/javascript">
10834 * @class Roo.data.SortTypes
10836 * Defines the default sorting (casting?) comparison functions used when sorting data.
10838 Roo.data.SortTypes = {
10840 * Default sort that does nothing
10841 * @param {Mixed} s The value being converted
10842 * @return {Mixed} The comparison value
10844 none : function(s){
10849 * The regular expression used to strip tags
10853 stripTagsRE : /<\/?[^>]+>/gi,
10856 * Strips all HTML tags to sort on text only
10857 * @param {Mixed} s The value being converted
10858 * @return {String} The comparison value
10860 asText : function(s){
10861 return String(s).replace(this.stripTagsRE, "");
10865 * Strips all HTML tags to sort on text only - Case insensitive
10866 * @param {Mixed} s The value being converted
10867 * @return {String} The comparison value
10869 asUCText : function(s){
10870 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10874 * Case insensitive string
10875 * @param {Mixed} s The value being converted
10876 * @return {String} The comparison value
10878 asUCString : function(s) {
10879 return String(s).toUpperCase();
10884 * @param {Mixed} s The value being converted
10885 * @return {Number} The comparison value
10887 asDate : function(s) {
10891 if(s instanceof Date){
10892 return s.getTime();
10894 return Date.parse(String(s));
10899 * @param {Mixed} s The value being converted
10900 * @return {Float} The comparison value
10902 asFloat : function(s) {
10903 var val = parseFloat(String(s).replace(/,/g, ""));
10912 * @param {Mixed} s The value being converted
10913 * @return {Number} The comparison value
10915 asInt : function(s) {
10916 var val = parseInt(String(s).replace(/,/g, ""));
10924 * Ext JS Library 1.1.1
10925 * Copyright(c) 2006-2007, Ext JS, LLC.
10927 * Originally Released Under LGPL - original licence link has changed is not relivant.
10930 * <script type="text/javascript">
10934 * @class Roo.data.Record
10935 * Instances of this class encapsulate both record <em>definition</em> information, and record
10936 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10937 * to access Records cached in an {@link Roo.data.Store} object.<br>
10939 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10940 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10943 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10945 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10946 * {@link #create}. The parameters are the same.
10947 * @param {Array} data An associative Array of data values keyed by the field name.
10948 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10949 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10950 * not specified an integer id is generated.
10952 Roo.data.Record = function(data, id){
10953 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10958 * Generate a constructor for a specific record layout.
10959 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10960 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10961 * Each field definition object may contain the following properties: <ul>
10962 * <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,
10963 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10964 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10965 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10966 * is being used, then this is a string containing the javascript expression to reference the data relative to
10967 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10968 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10969 * this may be omitted.</p></li>
10970 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10971 * <ul><li>auto (Default, implies no conversion)</li>
10976 * <li>date</li></ul></p></li>
10977 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10978 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10979 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10980 * by the Reader into an object that will be stored in the Record. It is passed the
10981 * following parameters:<ul>
10982 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10984 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10986 * <br>usage:<br><pre><code>
10987 var TopicRecord = Roo.data.Record.create(
10988 {name: 'title', mapping: 'topic_title'},
10989 {name: 'author', mapping: 'username'},
10990 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10991 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10992 {name: 'lastPoster', mapping: 'user2'},
10993 {name: 'excerpt', mapping: 'post_text'}
10996 var myNewRecord = new TopicRecord({
10997 title: 'Do my job please',
11000 lastPost: new Date(),
11001 lastPoster: 'Animal',
11002 excerpt: 'No way dude!'
11004 myStore.add(myNewRecord);
11009 Roo.data.Record.create = function(o){
11010 var f = function(){
11011 f.superclass.constructor.apply(this, arguments);
11013 Roo.extend(f, Roo.data.Record);
11014 var p = f.prototype;
11015 p.fields = new Roo.util.MixedCollection(false, function(field){
11018 for(var i = 0, len = o.length; i < len; i++){
11019 p.fields.add(new Roo.data.Field(o[i]));
11021 f.getField = function(name){
11022 return p.fields.get(name);
11027 Roo.data.Record.AUTO_ID = 1000;
11028 Roo.data.Record.EDIT = 'edit';
11029 Roo.data.Record.REJECT = 'reject';
11030 Roo.data.Record.COMMIT = 'commit';
11032 Roo.data.Record.prototype = {
11034 * Readonly flag - true if this record has been modified.
11043 join : function(store){
11044 this.store = store;
11048 * Set the named field to the specified value.
11049 * @param {String} name The name of the field to set.
11050 * @param {Object} value The value to set the field to.
11052 set : function(name, value){
11053 if(this.data[name] == value){
11057 if(!this.modified){
11058 this.modified = {};
11060 if(typeof this.modified[name] == 'undefined'){
11061 this.modified[name] = this.data[name];
11063 this.data[name] = value;
11064 if(!this.editing && this.store){
11065 this.store.afterEdit(this);
11070 * Get the value of the named field.
11071 * @param {String} name The name of the field to get the value of.
11072 * @return {Object} The value of the field.
11074 get : function(name){
11075 return this.data[name];
11079 beginEdit : function(){
11080 this.editing = true;
11081 this.modified = {};
11085 cancelEdit : function(){
11086 this.editing = false;
11087 delete this.modified;
11091 endEdit : function(){
11092 this.editing = false;
11093 if(this.dirty && this.store){
11094 this.store.afterEdit(this);
11099 * Usually called by the {@link Roo.data.Store} which owns the Record.
11100 * Rejects all changes made to the Record since either creation, or the last commit operation.
11101 * Modified fields are reverted to their original values.
11103 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11104 * of reject operations.
11106 reject : function(){
11107 var m = this.modified;
11109 if(typeof m[n] != "function"){
11110 this.data[n] = m[n];
11113 this.dirty = false;
11114 delete this.modified;
11115 this.editing = false;
11117 this.store.afterReject(this);
11122 * Usually called by the {@link Roo.data.Store} which owns the Record.
11123 * Commits all changes made to the Record since either creation, or the last commit operation.
11125 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11126 * of commit operations.
11128 commit : function(){
11129 this.dirty = false;
11130 delete this.modified;
11131 this.editing = false;
11133 this.store.afterCommit(this);
11138 hasError : function(){
11139 return this.error != null;
11143 clearError : function(){
11148 * Creates a copy of this record.
11149 * @param {String} id (optional) A new record id if you don't want to use this record's id
11152 copy : function(newId) {
11153 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11157 * Ext JS Library 1.1.1
11158 * Copyright(c) 2006-2007, Ext JS, LLC.
11160 * Originally Released Under LGPL - original licence link has changed is not relivant.
11163 * <script type="text/javascript">
11169 * @class Roo.data.Store
11170 * @extends Roo.util.Observable
11171 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11172 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11174 * 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
11175 * has no knowledge of the format of the data returned by the Proxy.<br>
11177 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11178 * instances from the data object. These records are cached and made available through accessor functions.
11180 * Creates a new Store.
11181 * @param {Object} config A config object containing the objects needed for the Store to access data,
11182 * and read the data into Records.
11184 Roo.data.Store = function(config){
11185 this.data = new Roo.util.MixedCollection(false);
11186 this.data.getKey = function(o){
11189 this.baseParams = {};
11191 this.paramNames = {
11196 "multisort" : "_multisort"
11199 if(config && config.data){
11200 this.inlineData = config.data;
11201 delete config.data;
11204 Roo.apply(this, config);
11206 if(this.reader){ // reader passed
11207 this.reader = Roo.factory(this.reader, Roo.data);
11208 this.reader.xmodule = this.xmodule || false;
11209 if(!this.recordType){
11210 this.recordType = this.reader.recordType;
11212 if(this.reader.onMetaChange){
11213 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11217 if(this.recordType){
11218 this.fields = this.recordType.prototype.fields;
11220 this.modified = [];
11224 * @event datachanged
11225 * Fires when the data cache has changed, and a widget which is using this Store
11226 * as a Record cache should refresh its view.
11227 * @param {Store} this
11229 datachanged : true,
11231 * @event metachange
11232 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11233 * @param {Store} this
11234 * @param {Object} meta The JSON metadata
11239 * Fires when Records have been added to the Store
11240 * @param {Store} this
11241 * @param {Roo.data.Record[]} records The array of Records added
11242 * @param {Number} index The index at which the record(s) were added
11247 * Fires when a Record has been removed from the Store
11248 * @param {Store} this
11249 * @param {Roo.data.Record} record The Record that was removed
11250 * @param {Number} index The index at which the record was removed
11255 * Fires when a Record has been updated
11256 * @param {Store} this
11257 * @param {Roo.data.Record} record The Record that was updated
11258 * @param {String} operation The update operation being performed. Value may be one of:
11260 Roo.data.Record.EDIT
11261 Roo.data.Record.REJECT
11262 Roo.data.Record.COMMIT
11268 * Fires when the data cache has been cleared.
11269 * @param {Store} this
11273 * @event beforeload
11274 * Fires before a request is made for a new data object. If the beforeload handler returns false
11275 * the load action will be canceled.
11276 * @param {Store} this
11277 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11281 * @event beforeloadadd
11282 * Fires after a new set of Records has been loaded.
11283 * @param {Store} this
11284 * @param {Roo.data.Record[]} records The Records that were loaded
11285 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11287 beforeloadadd : true,
11290 * Fires after a new set of Records has been loaded, before they are added to the store.
11291 * @param {Store} this
11292 * @param {Roo.data.Record[]} records The Records that were loaded
11293 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11294 * @params {Object} return from reader
11298 * @event loadexception
11299 * Fires if an exception occurs in the Proxy during loading.
11300 * Called with the signature of the Proxy's "loadexception" event.
11301 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11304 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11305 * @param {Object} load options
11306 * @param {Object} jsonData from your request (normally this contains the Exception)
11308 loadexception : true
11312 this.proxy = Roo.factory(this.proxy, Roo.data);
11313 this.proxy.xmodule = this.xmodule || false;
11314 this.relayEvents(this.proxy, ["loadexception"]);
11316 this.sortToggle = {};
11317 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11319 Roo.data.Store.superclass.constructor.call(this);
11321 if(this.inlineData){
11322 this.loadData(this.inlineData);
11323 delete this.inlineData;
11327 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11329 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11330 * without a remote query - used by combo/forms at present.
11334 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11337 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11340 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11341 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11344 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11345 * on any HTTP request
11348 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11351 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11355 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11356 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11358 remoteSort : false,
11361 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11362 * loaded or when a record is removed. (defaults to false).
11364 pruneModifiedRecords : false,
11367 lastOptions : null,
11370 * Add Records to the Store and fires the add event.
11371 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11373 add : function(records){
11374 records = [].concat(records);
11375 for(var i = 0, len = records.length; i < len; i++){
11376 records[i].join(this);
11378 var index = this.data.length;
11379 this.data.addAll(records);
11380 this.fireEvent("add", this, records, index);
11384 * Remove a Record from the Store and fires the remove event.
11385 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11387 remove : function(record){
11388 var index = this.data.indexOf(record);
11389 this.data.removeAt(index);
11391 if(this.pruneModifiedRecords){
11392 this.modified.remove(record);
11394 this.fireEvent("remove", this, record, index);
11398 * Remove all Records from the Store and fires the clear event.
11400 removeAll : function(){
11402 if(this.pruneModifiedRecords){
11403 this.modified = [];
11405 this.fireEvent("clear", this);
11409 * Inserts Records to the Store at the given index and fires the add event.
11410 * @param {Number} index The start index at which to insert the passed Records.
11411 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11413 insert : function(index, records){
11414 records = [].concat(records);
11415 for(var i = 0, len = records.length; i < len; i++){
11416 this.data.insert(index, records[i]);
11417 records[i].join(this);
11419 this.fireEvent("add", this, records, index);
11423 * Get the index within the cache of the passed Record.
11424 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11425 * @return {Number} The index of the passed Record. Returns -1 if not found.
11427 indexOf : function(record){
11428 return this.data.indexOf(record);
11432 * Get the index within the cache of the Record with the passed id.
11433 * @param {String} id The id of the Record to find.
11434 * @return {Number} The index of the Record. Returns -1 if not found.
11436 indexOfId : function(id){
11437 return this.data.indexOfKey(id);
11441 * Get the Record with the specified id.
11442 * @param {String} id The id of the Record to find.
11443 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11445 getById : function(id){
11446 return this.data.key(id);
11450 * Get the Record at the specified index.
11451 * @param {Number} index The index of the Record to find.
11452 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11454 getAt : function(index){
11455 return this.data.itemAt(index);
11459 * Returns a range of Records between specified indices.
11460 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11461 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11462 * @return {Roo.data.Record[]} An array of Records
11464 getRange : function(start, end){
11465 return this.data.getRange(start, end);
11469 storeOptions : function(o){
11470 o = Roo.apply({}, o);
11473 this.lastOptions = o;
11477 * Loads the Record cache from the configured Proxy using the configured Reader.
11479 * If using remote paging, then the first load call must specify the <em>start</em>
11480 * and <em>limit</em> properties in the options.params property to establish the initial
11481 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11483 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11484 * and this call will return before the new data has been loaded. Perform any post-processing
11485 * in a callback function, or in a "load" event handler.</strong>
11487 * @param {Object} options An object containing properties which control loading options:<ul>
11488 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11489 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11490 * passed the following arguments:<ul>
11491 * <li>r : Roo.data.Record[]</li>
11492 * <li>options: Options object from the load call</li>
11493 * <li>success: Boolean success indicator</li></ul></li>
11494 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11495 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11498 load : function(options){
11499 options = options || {};
11500 if(this.fireEvent("beforeload", this, options) !== false){
11501 this.storeOptions(options);
11502 var p = Roo.apply(options.params || {}, this.baseParams);
11503 // if meta was not loaded from remote source.. try requesting it.
11504 if (!this.reader.metaFromRemote) {
11505 p._requestMeta = 1;
11507 if(this.sortInfo && this.remoteSort){
11508 var pn = this.paramNames;
11509 p[pn["sort"]] = this.sortInfo.field;
11510 p[pn["dir"]] = this.sortInfo.direction;
11512 if (this.multiSort) {
11513 var pn = this.paramNames;
11514 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11517 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11522 * Reloads the Record cache from the configured Proxy using the configured Reader and
11523 * the options from the last load operation performed.
11524 * @param {Object} options (optional) An object containing properties which may override the options
11525 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11526 * the most recently used options are reused).
11528 reload : function(options){
11529 this.load(Roo.applyIf(options||{}, this.lastOptions));
11533 // Called as a callback by the Reader during a load operation.
11534 loadRecords : function(o, options, success){
11535 if(!o || success === false){
11536 if(success !== false){
11537 this.fireEvent("load", this, [], options, o);
11539 if(options.callback){
11540 options.callback.call(options.scope || this, [], options, false);
11544 // if data returned failure - throw an exception.
11545 if (o.success === false) {
11546 // show a message if no listener is registered.
11547 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11548 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11550 // loadmask wil be hooked into this..
11551 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11554 var r = o.records, t = o.totalRecords || r.length;
11556 this.fireEvent("beforeloadadd", this, r, options, o);
11558 if(!options || options.add !== true){
11559 if(this.pruneModifiedRecords){
11560 this.modified = [];
11562 for(var i = 0, len = r.length; i < len; i++){
11566 this.data = this.snapshot;
11567 delete this.snapshot;
11570 this.data.addAll(r);
11571 this.totalLength = t;
11573 this.fireEvent("datachanged", this);
11575 this.totalLength = Math.max(t, this.data.length+r.length);
11579 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11581 var e = new Roo.data.Record({});
11583 e.set(this.parent.displayField, this.parent.emptyTitle);
11584 e.set(this.parent.valueField, '');
11589 this.fireEvent("load", this, r, options, o);
11590 if(options.callback){
11591 options.callback.call(options.scope || this, r, options, true);
11597 * Loads data from a passed data block. A Reader which understands the format of the data
11598 * must have been configured in the constructor.
11599 * @param {Object} data The data block from which to read the Records. The format of the data expected
11600 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11601 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11603 loadData : function(o, append){
11604 var r = this.reader.readRecords(o);
11605 this.loadRecords(r, {add: append}, true);
11609 * Gets the number of cached records.
11611 * <em>If using paging, this may not be the total size of the dataset. If the data object
11612 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11613 * the data set size</em>
11615 getCount : function(){
11616 return this.data.length || 0;
11620 * Gets the total number of records in the dataset as returned by the server.
11622 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11623 * the dataset size</em>
11625 getTotalCount : function(){
11626 return this.totalLength || 0;
11630 * Returns the sort state of the Store as an object with two properties:
11632 field {String} The name of the field by which the Records are sorted
11633 direction {String} The sort order, "ASC" or "DESC"
11636 getSortState : function(){
11637 return this.sortInfo;
11641 applySort : function(){
11642 if(this.sortInfo && !this.remoteSort){
11643 var s = this.sortInfo, f = s.field;
11644 var st = this.fields.get(f).sortType;
11645 var fn = function(r1, r2){
11646 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11647 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11649 this.data.sort(s.direction, fn);
11650 if(this.snapshot && this.snapshot != this.data){
11651 this.snapshot.sort(s.direction, fn);
11657 * Sets the default sort column and order to be used by the next load operation.
11658 * @param {String} fieldName The name of the field to sort by.
11659 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11661 setDefaultSort : function(field, dir){
11662 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11666 * Sort the Records.
11667 * If remote sorting is used, the sort is performed on the server, and the cache is
11668 * reloaded. If local sorting is used, the cache is sorted internally.
11669 * @param {String} fieldName The name of the field to sort by.
11670 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11672 sort : function(fieldName, dir){
11673 var f = this.fields.get(fieldName);
11675 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11677 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11678 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11683 this.sortToggle[f.name] = dir;
11684 this.sortInfo = {field: f.name, direction: dir};
11685 if(!this.remoteSort){
11687 this.fireEvent("datachanged", this);
11689 this.load(this.lastOptions);
11694 * Calls the specified function for each of the Records in the cache.
11695 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11696 * Returning <em>false</em> aborts and exits the iteration.
11697 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11699 each : function(fn, scope){
11700 this.data.each(fn, scope);
11704 * Gets all records modified since the last commit. Modified records are persisted across load operations
11705 * (e.g., during paging).
11706 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11708 getModifiedRecords : function(){
11709 return this.modified;
11713 createFilterFn : function(property, value, anyMatch){
11714 if(!value.exec){ // not a regex
11715 value = String(value);
11716 if(value.length == 0){
11719 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11721 return function(r){
11722 return value.test(r.data[property]);
11727 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11728 * @param {String} property A field on your records
11729 * @param {Number} start The record index to start at (defaults to 0)
11730 * @param {Number} end The last record index to include (defaults to length - 1)
11731 * @return {Number} The sum
11733 sum : function(property, start, end){
11734 var rs = this.data.items, v = 0;
11735 start = start || 0;
11736 end = (end || end === 0) ? end : rs.length-1;
11738 for(var i = start; i <= end; i++){
11739 v += (rs[i].data[property] || 0);
11745 * Filter the records by a specified property.
11746 * @param {String} field A field on your records
11747 * @param {String/RegExp} value Either a string that the field
11748 * should start with or a RegExp to test against the field
11749 * @param {Boolean} anyMatch True to match any part not just the beginning
11751 filter : function(property, value, anyMatch){
11752 var fn = this.createFilterFn(property, value, anyMatch);
11753 return fn ? this.filterBy(fn) : this.clearFilter();
11757 * Filter by a function. The specified function will be called with each
11758 * record in this data source. If the function returns true the record is included,
11759 * otherwise it is filtered.
11760 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11761 * @param {Object} scope (optional) The scope of the function (defaults to this)
11763 filterBy : function(fn, scope){
11764 this.snapshot = this.snapshot || this.data;
11765 this.data = this.queryBy(fn, scope||this);
11766 this.fireEvent("datachanged", this);
11770 * Query the records by a specified property.
11771 * @param {String} field A field on your records
11772 * @param {String/RegExp} value Either a string that the field
11773 * should start with or a RegExp to test against the field
11774 * @param {Boolean} anyMatch True to match any part not just the beginning
11775 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11777 query : function(property, value, anyMatch){
11778 var fn = this.createFilterFn(property, value, anyMatch);
11779 return fn ? this.queryBy(fn) : this.data.clone();
11783 * Query by a function. The specified function will be called with each
11784 * record in this data source. If the function returns true the record is included
11786 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11787 * @param {Object} scope (optional) The scope of the function (defaults to this)
11788 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11790 queryBy : function(fn, scope){
11791 var data = this.snapshot || this.data;
11792 return data.filterBy(fn, scope||this);
11796 * Collects unique values for a particular dataIndex from this store.
11797 * @param {String} dataIndex The property to collect
11798 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11799 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11800 * @return {Array} An array of the unique values
11802 collect : function(dataIndex, allowNull, bypassFilter){
11803 var d = (bypassFilter === true && this.snapshot) ?
11804 this.snapshot.items : this.data.items;
11805 var v, sv, r = [], l = {};
11806 for(var i = 0, len = d.length; i < len; i++){
11807 v = d[i].data[dataIndex];
11809 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11818 * Revert to a view of the Record cache with no filtering applied.
11819 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11821 clearFilter : function(suppressEvent){
11822 if(this.snapshot && this.snapshot != this.data){
11823 this.data = this.snapshot;
11824 delete this.snapshot;
11825 if(suppressEvent !== true){
11826 this.fireEvent("datachanged", this);
11832 afterEdit : function(record){
11833 if(this.modified.indexOf(record) == -1){
11834 this.modified.push(record);
11836 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11840 afterReject : function(record){
11841 this.modified.remove(record);
11842 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11846 afterCommit : function(record){
11847 this.modified.remove(record);
11848 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11852 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11853 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11855 commitChanges : function(){
11856 var m = this.modified.slice(0);
11857 this.modified = [];
11858 for(var i = 0, len = m.length; i < len; i++){
11864 * Cancel outstanding changes on all changed records.
11866 rejectChanges : function(){
11867 var m = this.modified.slice(0);
11868 this.modified = [];
11869 for(var i = 0, len = m.length; i < len; i++){
11874 onMetaChange : function(meta, rtype, o){
11875 this.recordType = rtype;
11876 this.fields = rtype.prototype.fields;
11877 delete this.snapshot;
11878 this.sortInfo = meta.sortInfo || this.sortInfo;
11879 this.modified = [];
11880 this.fireEvent('metachange', this, this.reader.meta);
11883 moveIndex : function(data, type)
11885 var index = this.indexOf(data);
11887 var newIndex = index + type;
11891 this.insert(newIndex, data);
11896 * Ext JS Library 1.1.1
11897 * Copyright(c) 2006-2007, Ext JS, LLC.
11899 * Originally Released Under LGPL - original licence link has changed is not relivant.
11902 * <script type="text/javascript">
11906 * @class Roo.data.SimpleStore
11907 * @extends Roo.data.Store
11908 * Small helper class to make creating Stores from Array data easier.
11909 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11910 * @cfg {Array} fields An array of field definition objects, or field name strings.
11911 * @cfg {Array} data The multi-dimensional array of data
11913 * @param {Object} config
11915 Roo.data.SimpleStore = function(config){
11916 Roo.data.SimpleStore.superclass.constructor.call(this, {
11918 reader: new Roo.data.ArrayReader({
11921 Roo.data.Record.create(config.fields)
11923 proxy : new Roo.data.MemoryProxy(config.data)
11927 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11929 * Ext JS Library 1.1.1
11930 * Copyright(c) 2006-2007, Ext JS, LLC.
11932 * Originally Released Under LGPL - original licence link has changed is not relivant.
11935 * <script type="text/javascript">
11940 * @extends Roo.data.Store
11941 * @class Roo.data.JsonStore
11942 * Small helper class to make creating Stores for JSON data easier. <br/>
11944 var store = new Roo.data.JsonStore({
11945 url: 'get-images.php',
11947 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11950 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11951 * JsonReader and HttpProxy (unless inline data is provided).</b>
11952 * @cfg {Array} fields An array of field definition objects, or field name strings.
11954 * @param {Object} config
11956 Roo.data.JsonStore = function(c){
11957 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11958 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11959 reader: new Roo.data.JsonReader(c, c.fields)
11962 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11964 * Ext JS Library 1.1.1
11965 * Copyright(c) 2006-2007, Ext JS, LLC.
11967 * Originally Released Under LGPL - original licence link has changed is not relivant.
11970 * <script type="text/javascript">
11974 Roo.data.Field = function(config){
11975 if(typeof config == "string"){
11976 config = {name: config};
11978 Roo.apply(this, config);
11981 this.type = "auto";
11984 var st = Roo.data.SortTypes;
11985 // named sortTypes are supported, here we look them up
11986 if(typeof this.sortType == "string"){
11987 this.sortType = st[this.sortType];
11990 // set default sortType for strings and dates
11991 if(!this.sortType){
11994 this.sortType = st.asUCString;
11997 this.sortType = st.asDate;
12000 this.sortType = st.none;
12005 var stripRe = /[\$,%]/g;
12007 // prebuilt conversion function for this field, instead of
12008 // switching every time we're reading a value
12010 var cv, dateFormat = this.dateFormat;
12015 cv = function(v){ return v; };
12018 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12022 return v !== undefined && v !== null && v !== '' ?
12023 parseInt(String(v).replace(stripRe, ""), 10) : '';
12028 return v !== undefined && v !== null && v !== '' ?
12029 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12034 cv = function(v){ return v === true || v === "true" || v == 1; };
12041 if(v instanceof Date){
12045 if(dateFormat == "timestamp"){
12046 return new Date(v*1000);
12048 return Date.parseDate(v, dateFormat);
12050 var parsed = Date.parse(v);
12051 return parsed ? new Date(parsed) : null;
12060 Roo.data.Field.prototype = {
12068 * Ext JS Library 1.1.1
12069 * Copyright(c) 2006-2007, Ext JS, LLC.
12071 * Originally Released Under LGPL - original licence link has changed is not relivant.
12074 * <script type="text/javascript">
12077 // Base class for reading structured data from a data source. This class is intended to be
12078 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12081 * @class Roo.data.DataReader
12082 * Base class for reading structured data from a data source. This class is intended to be
12083 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12086 Roo.data.DataReader = function(meta, recordType){
12090 this.recordType = recordType instanceof Array ?
12091 Roo.data.Record.create(recordType) : recordType;
12094 Roo.data.DataReader.prototype = {
12096 * Create an empty record
12097 * @param {Object} data (optional) - overlay some values
12098 * @return {Roo.data.Record} record created.
12100 newRow : function(d) {
12102 this.recordType.prototype.fields.each(function(c) {
12104 case 'int' : da[c.name] = 0; break;
12105 case 'date' : da[c.name] = new Date(); break;
12106 case 'float' : da[c.name] = 0.0; break;
12107 case 'boolean' : da[c.name] = false; break;
12108 default : da[c.name] = ""; break;
12112 return new this.recordType(Roo.apply(da, d));
12117 * Ext JS Library 1.1.1
12118 * Copyright(c) 2006-2007, Ext JS, LLC.
12120 * Originally Released Under LGPL - original licence link has changed is not relivant.
12123 * <script type="text/javascript">
12127 * @class Roo.data.DataProxy
12128 * @extends Roo.data.Observable
12129 * This class is an abstract base class for implementations which provide retrieval of
12130 * unformatted data objects.<br>
12132 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12133 * (of the appropriate type which knows how to parse the data object) to provide a block of
12134 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12136 * Custom implementations must implement the load method as described in
12137 * {@link Roo.data.HttpProxy#load}.
12139 Roo.data.DataProxy = function(){
12142 * @event beforeload
12143 * Fires before a network request is made to retrieve a data object.
12144 * @param {Object} This DataProxy object.
12145 * @param {Object} params The params parameter to the load function.
12150 * Fires before the load method's callback is called.
12151 * @param {Object} This DataProxy object.
12152 * @param {Object} o The data object.
12153 * @param {Object} arg The callback argument object passed to the load function.
12157 * @event loadexception
12158 * Fires if an Exception occurs during data retrieval.
12159 * @param {Object} This DataProxy object.
12160 * @param {Object} o The data object.
12161 * @param {Object} arg The callback argument object passed to the load function.
12162 * @param {Object} e The Exception.
12164 loadexception : true
12166 Roo.data.DataProxy.superclass.constructor.call(this);
12169 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12172 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12176 * Ext JS Library 1.1.1
12177 * Copyright(c) 2006-2007, Ext JS, LLC.
12179 * Originally Released Under LGPL - original licence link has changed is not relivant.
12182 * <script type="text/javascript">
12185 * @class Roo.data.MemoryProxy
12186 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12187 * to the Reader when its load method is called.
12189 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12191 Roo.data.MemoryProxy = function(data){
12195 Roo.data.MemoryProxy.superclass.constructor.call(this);
12199 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12202 * Load data from the requested source (in this case an in-memory
12203 * data object passed to the constructor), read the data object into
12204 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12205 * process that block using the passed callback.
12206 * @param {Object} params This parameter is not used by the MemoryProxy class.
12207 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12208 * object into a block of Roo.data.Records.
12209 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12210 * The function must be passed <ul>
12211 * <li>The Record block object</li>
12212 * <li>The "arg" argument from the load function</li>
12213 * <li>A boolean success indicator</li>
12215 * @param {Object} scope The scope in which to call the callback
12216 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12218 load : function(params, reader, callback, scope, arg){
12219 params = params || {};
12222 result = reader.readRecords(this.data);
12224 this.fireEvent("loadexception", this, arg, null, e);
12225 callback.call(scope, null, arg, false);
12228 callback.call(scope, result, arg, true);
12232 update : function(params, records){
12237 * Ext JS Library 1.1.1
12238 * Copyright(c) 2006-2007, Ext JS, LLC.
12240 * Originally Released Under LGPL - original licence link has changed is not relivant.
12243 * <script type="text/javascript">
12246 * @class Roo.data.HttpProxy
12247 * @extends Roo.data.DataProxy
12248 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12249 * configured to reference a certain URL.<br><br>
12251 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12252 * from which the running page was served.<br><br>
12254 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12256 * Be aware that to enable the browser to parse an XML document, the server must set
12257 * the Content-Type header in the HTTP response to "text/xml".
12259 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12260 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12261 * will be used to make the request.
12263 Roo.data.HttpProxy = function(conn){
12264 Roo.data.HttpProxy.superclass.constructor.call(this);
12265 // is conn a conn config or a real conn?
12267 this.useAjax = !conn || !conn.events;
12271 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12272 // thse are take from connection...
12275 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12278 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12279 * extra parameters to each request made by this object. (defaults to undefined)
12282 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12283 * to each request made by this object. (defaults to undefined)
12286 * @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)
12289 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12292 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12298 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12302 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12303 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12304 * a finer-grained basis than the DataProxy events.
12306 getConnection : function(){
12307 return this.useAjax ? Roo.Ajax : this.conn;
12311 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12312 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12313 * process that block using the passed callback.
12314 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12315 * for the request to the remote server.
12316 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12317 * object into a block of Roo.data.Records.
12318 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12319 * The function must be passed <ul>
12320 * <li>The Record block object</li>
12321 * <li>The "arg" argument from the load function</li>
12322 * <li>A boolean success indicator</li>
12324 * @param {Object} scope The scope in which to call the callback
12325 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12327 load : function(params, reader, callback, scope, arg){
12328 if(this.fireEvent("beforeload", this, params) !== false){
12330 params : params || {},
12332 callback : callback,
12337 callback : this.loadResponse,
12341 Roo.applyIf(o, this.conn);
12342 if(this.activeRequest){
12343 Roo.Ajax.abort(this.activeRequest);
12345 this.activeRequest = Roo.Ajax.request(o);
12347 this.conn.request(o);
12350 callback.call(scope||this, null, arg, false);
12355 loadResponse : function(o, success, response){
12356 delete this.activeRequest;
12358 this.fireEvent("loadexception", this, o, response);
12359 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12364 result = o.reader.read(response);
12366 this.fireEvent("loadexception", this, o, response, e);
12367 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12371 this.fireEvent("load", this, o, o.request.arg);
12372 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12376 update : function(dataSet){
12381 updateResponse : function(dataSet){
12386 * Ext JS Library 1.1.1
12387 * Copyright(c) 2006-2007, Ext JS, LLC.
12389 * Originally Released Under LGPL - original licence link has changed is not relivant.
12392 * <script type="text/javascript">
12396 * @class Roo.data.ScriptTagProxy
12397 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12398 * other than the originating domain of the running page.<br><br>
12400 * <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
12401 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12403 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12404 * source code that is used as the source inside a <script> tag.<br><br>
12406 * In order for the browser to process the returned data, the server must wrap the data object
12407 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12408 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12409 * depending on whether the callback name was passed:
12412 boolean scriptTag = false;
12413 String cb = request.getParameter("callback");
12416 response.setContentType("text/javascript");
12418 response.setContentType("application/x-json");
12420 Writer out = response.getWriter();
12422 out.write(cb + "(");
12424 out.print(dataBlock.toJsonString());
12431 * @param {Object} config A configuration object.
12433 Roo.data.ScriptTagProxy = function(config){
12434 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12435 Roo.apply(this, config);
12436 this.head = document.getElementsByTagName("head")[0];
12439 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12441 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12443 * @cfg {String} url The URL from which to request the data object.
12446 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12450 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12451 * the server the name of the callback function set up by the load call to process the returned data object.
12452 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12453 * javascript output which calls this named function passing the data object as its only parameter.
12455 callbackParam : "callback",
12457 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12458 * name to the request.
12463 * Load data from the configured URL, read the data object into
12464 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12465 * process that block using the passed callback.
12466 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12467 * for the request to the remote server.
12468 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12469 * object into a block of Roo.data.Records.
12470 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12471 * The function must be passed <ul>
12472 * <li>The Record block object</li>
12473 * <li>The "arg" argument from the load function</li>
12474 * <li>A boolean success indicator</li>
12476 * @param {Object} scope The scope in which to call the callback
12477 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12479 load : function(params, reader, callback, scope, arg){
12480 if(this.fireEvent("beforeload", this, params) !== false){
12482 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12484 var url = this.url;
12485 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12487 url += "&_dc=" + (new Date().getTime());
12489 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12492 cb : "stcCallback"+transId,
12493 scriptId : "stcScript"+transId,
12497 callback : callback,
12503 window[trans.cb] = function(o){
12504 conn.handleResponse(o, trans);
12507 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12509 if(this.autoAbort !== false){
12513 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12515 var script = document.createElement("script");
12516 script.setAttribute("src", url);
12517 script.setAttribute("type", "text/javascript");
12518 script.setAttribute("id", trans.scriptId);
12519 this.head.appendChild(script);
12521 this.trans = trans;
12523 callback.call(scope||this, null, arg, false);
12528 isLoading : function(){
12529 return this.trans ? true : false;
12533 * Abort the current server request.
12535 abort : function(){
12536 if(this.isLoading()){
12537 this.destroyTrans(this.trans);
12542 destroyTrans : function(trans, isLoaded){
12543 this.head.removeChild(document.getElementById(trans.scriptId));
12544 clearTimeout(trans.timeoutId);
12546 window[trans.cb] = undefined;
12548 delete window[trans.cb];
12551 // if hasn't been loaded, wait for load to remove it to prevent script error
12552 window[trans.cb] = function(){
12553 window[trans.cb] = undefined;
12555 delete window[trans.cb];
12562 handleResponse : function(o, trans){
12563 this.trans = false;
12564 this.destroyTrans(trans, true);
12567 result = trans.reader.readRecords(o);
12569 this.fireEvent("loadexception", this, o, trans.arg, e);
12570 trans.callback.call(trans.scope||window, null, trans.arg, false);
12573 this.fireEvent("load", this, o, trans.arg);
12574 trans.callback.call(trans.scope||window, result, trans.arg, true);
12578 handleFailure : function(trans){
12579 this.trans = false;
12580 this.destroyTrans(trans, false);
12581 this.fireEvent("loadexception", this, null, trans.arg);
12582 trans.callback.call(trans.scope||window, null, trans.arg, false);
12586 * Ext JS Library 1.1.1
12587 * Copyright(c) 2006-2007, Ext JS, LLC.
12589 * Originally Released Under LGPL - original licence link has changed is not relivant.
12592 * <script type="text/javascript">
12596 * @class Roo.data.JsonReader
12597 * @extends Roo.data.DataReader
12598 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12599 * based on mappings in a provided Roo.data.Record constructor.
12601 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12602 * in the reply previously.
12607 var RecordDef = Roo.data.Record.create([
12608 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12609 {name: 'occupation'} // This field will use "occupation" as the mapping.
12611 var myReader = new Roo.data.JsonReader({
12612 totalProperty: "results", // The property which contains the total dataset size (optional)
12613 root: "rows", // The property which contains an Array of row objects
12614 id: "id" // The property within each row object that provides an ID for the record (optional)
12618 * This would consume a JSON file like this:
12620 { 'results': 2, 'rows': [
12621 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12622 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12625 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12626 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12627 * paged from the remote server.
12628 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12629 * @cfg {String} root name of the property which contains the Array of row objects.
12630 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12631 * @cfg {Array} fields Array of field definition objects
12633 * Create a new JsonReader
12634 * @param {Object} meta Metadata configuration options
12635 * @param {Object} recordType Either an Array of field definition objects,
12636 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12638 Roo.data.JsonReader = function(meta, recordType){
12641 // set some defaults:
12642 Roo.applyIf(meta, {
12643 totalProperty: 'total',
12644 successProperty : 'success',
12649 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12651 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12654 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12655 * Used by Store query builder to append _requestMeta to params.
12658 metaFromRemote : false,
12660 * This method is only used by a DataProxy which has retrieved data from a remote server.
12661 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12662 * @return {Object} data A data block which is used by an Roo.data.Store object as
12663 * a cache of Roo.data.Records.
12665 read : function(response){
12666 var json = response.responseText;
12668 var o = /* eval:var:o */ eval("("+json+")");
12670 throw {message: "JsonReader.read: Json object not found"};
12676 this.metaFromRemote = true;
12677 this.meta = o.metaData;
12678 this.recordType = Roo.data.Record.create(o.metaData.fields);
12679 this.onMetaChange(this.meta, this.recordType, o);
12681 return this.readRecords(o);
12684 // private function a store will implement
12685 onMetaChange : function(meta, recordType, o){
12692 simpleAccess: function(obj, subsc) {
12699 getJsonAccessor: function(){
12701 return function(expr) {
12703 return(re.test(expr))
12704 ? new Function("obj", "return obj." + expr)
12709 return Roo.emptyFn;
12714 * Create a data block containing Roo.data.Records from an XML document.
12715 * @param {Object} o An object which contains an Array of row objects in the property specified
12716 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12717 * which contains the total size of the dataset.
12718 * @return {Object} data A data block which is used by an Roo.data.Store object as
12719 * a cache of Roo.data.Records.
12721 readRecords : function(o){
12723 * After any data loads, the raw JSON data is available for further custom processing.
12727 var s = this.meta, Record = this.recordType,
12728 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12730 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12732 if(s.totalProperty) {
12733 this.getTotal = this.getJsonAccessor(s.totalProperty);
12735 if(s.successProperty) {
12736 this.getSuccess = this.getJsonAccessor(s.successProperty);
12738 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12740 var g = this.getJsonAccessor(s.id);
12741 this.getId = function(rec) {
12743 return (r === undefined || r === "") ? null : r;
12746 this.getId = function(){return null;};
12749 for(var jj = 0; jj < fl; jj++){
12751 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12752 this.ef[jj] = this.getJsonAccessor(map);
12756 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12757 if(s.totalProperty){
12758 var vt = parseInt(this.getTotal(o), 10);
12763 if(s.successProperty){
12764 var vs = this.getSuccess(o);
12765 if(vs === false || vs === 'false'){
12770 for(var i = 0; i < c; i++){
12773 var id = this.getId(n);
12774 for(var j = 0; j < fl; j++){
12776 var v = this.ef[j](n);
12778 Roo.log('missing convert for ' + f.name);
12782 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12784 var record = new Record(values, id);
12786 records[i] = record;
12792 totalRecords : totalRecords
12797 * Ext JS Library 1.1.1
12798 * Copyright(c) 2006-2007, Ext JS, LLC.
12800 * Originally Released Under LGPL - original licence link has changed is not relivant.
12803 * <script type="text/javascript">
12807 * @class Roo.data.ArrayReader
12808 * @extends Roo.data.DataReader
12809 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12810 * Each element of that Array represents a row of data fields. The
12811 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12812 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12816 var RecordDef = Roo.data.Record.create([
12817 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12818 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12820 var myReader = new Roo.data.ArrayReader({
12821 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12825 * This would consume an Array like this:
12827 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12829 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12831 * Create a new JsonReader
12832 * @param {Object} meta Metadata configuration options.
12833 * @param {Object} recordType Either an Array of field definition objects
12834 * as specified to {@link Roo.data.Record#create},
12835 * or an {@link Roo.data.Record} object
12836 * created using {@link Roo.data.Record#create}.
12838 Roo.data.ArrayReader = function(meta, recordType){
12839 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12842 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12844 * Create a data block containing Roo.data.Records from an XML document.
12845 * @param {Object} o An Array of row objects which represents the dataset.
12846 * @return {Object} data A data block which is used by an Roo.data.Store object as
12847 * a cache of Roo.data.Records.
12849 readRecords : function(o){
12850 var sid = this.meta ? this.meta.id : null;
12851 var recordType = this.recordType, fields = recordType.prototype.fields;
12854 for(var i = 0; i < root.length; i++){
12857 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12858 for(var j = 0, jlen = fields.length; j < jlen; j++){
12859 var f = fields.items[j];
12860 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12861 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12863 values[f.name] = v;
12865 var record = new recordType(values, id);
12867 records[records.length] = record;
12871 totalRecords : records.length
12880 * @class Roo.bootstrap.ComboBox
12881 * @extends Roo.bootstrap.TriggerField
12882 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12883 * @cfg {Boolean} append (true|false) default false
12884 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12885 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12886 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12887 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12888 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12889 * @cfg {Boolean} animate default true
12890 * @cfg {Boolean} emptyResultText only for touch device
12891 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12892 * @cfg {String} emptyTitle default ''
12894 * Create a new ComboBox.
12895 * @param {Object} config Configuration options
12897 Roo.bootstrap.ComboBox = function(config){
12898 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12902 * Fires when the dropdown list is expanded
12903 * @param {Roo.bootstrap.ComboBox} combo This combo box
12908 * Fires when the dropdown list is collapsed
12909 * @param {Roo.bootstrap.ComboBox} combo This combo box
12913 * @event beforeselect
12914 * Fires before a list item is selected. Return false to cancel the selection.
12915 * @param {Roo.bootstrap.ComboBox} combo This combo box
12916 * @param {Roo.data.Record} record The data record returned from the underlying store
12917 * @param {Number} index The index of the selected item in the dropdown list
12919 'beforeselect' : true,
12922 * Fires when a list item is selected
12923 * @param {Roo.bootstrap.ComboBox} combo This combo box
12924 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12925 * @param {Number} index The index of the selected item in the dropdown list
12929 * @event beforequery
12930 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12931 * The event object passed has these properties:
12932 * @param {Roo.bootstrap.ComboBox} combo This combo box
12933 * @param {String} query The query
12934 * @param {Boolean} forceAll true to force "all" query
12935 * @param {Boolean} cancel true to cancel the query
12936 * @param {Object} e The query event object
12938 'beforequery': true,
12941 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12942 * @param {Roo.bootstrap.ComboBox} combo This combo box
12947 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12948 * @param {Roo.bootstrap.ComboBox} combo This combo box
12949 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12954 * Fires when the remove value from the combobox array
12955 * @param {Roo.bootstrap.ComboBox} combo This combo box
12959 * @event afterremove
12960 * Fires when the remove value from the combobox array
12961 * @param {Roo.bootstrap.ComboBox} combo This combo box
12963 'afterremove' : true,
12965 * @event specialfilter
12966 * Fires when specialfilter
12967 * @param {Roo.bootstrap.ComboBox} combo This combo box
12969 'specialfilter' : true,
12972 * Fires when tick the element
12973 * @param {Roo.bootstrap.ComboBox} combo This combo box
12977 * @event touchviewdisplay
12978 * Fires when touch view require special display (default is using displayField)
12979 * @param {Roo.bootstrap.ComboBox} combo This combo box
12980 * @param {Object} cfg set html .
12982 'touchviewdisplay' : true
12987 this.tickItems = [];
12989 this.selectedIndex = -1;
12990 if(this.mode == 'local'){
12991 if(config.queryDelay === undefined){
12992 this.queryDelay = 10;
12994 if(config.minChars === undefined){
13000 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13003 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13004 * rendering into an Roo.Editor, defaults to false)
13007 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13008 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13011 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13014 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13015 * the dropdown list (defaults to undefined, with no header element)
13019 * @cfg {String/Roo.Template} tpl The template to use to render the output
13023 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13025 listWidth: undefined,
13027 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13028 * mode = 'remote' or 'text' if mode = 'local')
13030 displayField: undefined,
13033 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13034 * mode = 'remote' or 'value' if mode = 'local').
13035 * Note: use of a valueField requires the user make a selection
13036 * in order for a value to be mapped.
13038 valueField: undefined,
13040 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13045 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13046 * field's data value (defaults to the underlying DOM element's name)
13048 hiddenName: undefined,
13050 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13054 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13056 selectedClass: 'active',
13059 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13063 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13064 * anchor positions (defaults to 'tl-bl')
13066 listAlign: 'tl-bl?',
13068 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13072 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13073 * query specified by the allQuery config option (defaults to 'query')
13075 triggerAction: 'query',
13077 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13078 * (defaults to 4, does not apply if editable = false)
13082 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13083 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13087 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13088 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13092 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13093 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13097 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13098 * when editable = true (defaults to false)
13100 selectOnFocus:false,
13102 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13104 queryParam: 'query',
13106 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13107 * when mode = 'remote' (defaults to 'Loading...')
13109 loadingText: 'Loading...',
13111 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13115 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13119 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13120 * traditional select (defaults to true)
13124 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13128 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13132 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13133 * listWidth has a higher value)
13137 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13138 * allow the user to set arbitrary text into the field (defaults to false)
13140 forceSelection:false,
13142 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13143 * if typeAhead = true (defaults to 250)
13145 typeAheadDelay : 250,
13147 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13148 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13150 valueNotFoundText : undefined,
13152 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13154 blockFocus : false,
13157 * @cfg {Boolean} disableClear Disable showing of clear button.
13159 disableClear : false,
13161 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13163 alwaysQuery : false,
13166 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13171 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13173 invalidClass : "has-warning",
13176 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13178 validClass : "has-success",
13181 * @cfg {Boolean} specialFilter (true|false) special filter default false
13183 specialFilter : false,
13186 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13188 mobileTouchView : true,
13191 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13193 useNativeIOS : false,
13196 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13198 mobile_restrict_height : false,
13200 ios_options : false,
13212 btnPosition : 'right',
13213 triggerList : true,
13214 showToggleBtn : true,
13216 emptyResultText: 'Empty',
13217 triggerText : 'Select',
13220 // element that contains real text value.. (when hidden is used..)
13222 getAutoCreate : function()
13227 * Render classic select for iso
13230 if(Roo.isIOS && this.useNativeIOS){
13231 cfg = this.getAutoCreateNativeIOS();
13239 if(Roo.isTouch && this.mobileTouchView){
13240 cfg = this.getAutoCreateTouchView();
13247 if(!this.tickable){
13248 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13253 * ComboBox with tickable selections
13256 var align = this.labelAlign || this.parentLabelAlign();
13259 cls : 'form-group roo-combobox-tickable' //input-group
13262 var btn_text_select = '';
13263 var btn_text_done = '';
13264 var btn_text_cancel = '';
13266 if (this.btn_text_show) {
13267 btn_text_select = 'Select';
13268 btn_text_done = 'Done';
13269 btn_text_cancel = 'Cancel';
13274 cls : 'tickable-buttons',
13279 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13280 //html : this.triggerText
13281 html: btn_text_select
13287 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13289 html: btn_text_done
13295 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13297 html: btn_text_cancel
13303 buttons.cn.unshift({
13305 cls: 'roo-select2-search-field-input'
13311 Roo.each(buttons.cn, function(c){
13313 c.cls += ' btn-' + _this.size;
13316 if (_this.disabled) {
13327 cls: 'form-hidden-field'
13331 cls: 'roo-select2-choices',
13335 cls: 'roo-select2-search-field',
13346 cls: 'roo-select2-container input-group roo-select2-container-multi',
13352 // cls: 'typeahead typeahead-long dropdown-menu',
13353 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13358 if(this.hasFeedback && !this.allowBlank){
13362 cls: 'glyphicon form-control-feedback'
13365 combobox.cn.push(feedback);
13370 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13371 tooltip : 'This field is required'
13373 if (Roo.bootstrap.version == 4) {
13376 style : 'display:none'
13379 if (align ==='left' && this.fieldLabel.length) {
13381 cfg.cls += ' roo-form-group-label-left row';
13388 cls : 'control-label col-form-label',
13389 html : this.fieldLabel
13401 var labelCfg = cfg.cn[1];
13402 var contentCfg = cfg.cn[2];
13405 if(this.indicatorpos == 'right'){
13411 cls : 'control-label col-form-label',
13415 html : this.fieldLabel
13431 labelCfg = cfg.cn[0];
13432 contentCfg = cfg.cn[1];
13436 if(this.labelWidth > 12){
13437 labelCfg.style = "width: " + this.labelWidth + 'px';
13440 if(this.labelWidth < 13 && this.labelmd == 0){
13441 this.labelmd = this.labelWidth;
13444 if(this.labellg > 0){
13445 labelCfg.cls += ' col-lg-' + this.labellg;
13446 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13449 if(this.labelmd > 0){
13450 labelCfg.cls += ' col-md-' + this.labelmd;
13451 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13454 if(this.labelsm > 0){
13455 labelCfg.cls += ' col-sm-' + this.labelsm;
13456 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13459 if(this.labelxs > 0){
13460 labelCfg.cls += ' col-xs-' + this.labelxs;
13461 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13465 } else if ( this.fieldLabel.length) {
13466 // Roo.log(" label");
13471 //cls : 'input-group-addon',
13472 html : this.fieldLabel
13477 if(this.indicatorpos == 'right'){
13481 //cls : 'input-group-addon',
13482 html : this.fieldLabel
13492 // Roo.log(" no label && no align");
13499 ['xs','sm','md','lg'].map(function(size){
13500 if (settings[size]) {
13501 cfg.cls += ' col-' + size + '-' + settings[size];
13509 _initEventsCalled : false,
13512 initEvents: function()
13514 if (this._initEventsCalled) { // as we call render... prevent looping...
13517 this._initEventsCalled = true;
13520 throw "can not find store for combo";
13523 this.indicator = this.indicatorEl();
13525 this.store = Roo.factory(this.store, Roo.data);
13526 this.store.parent = this;
13528 // if we are building from html. then this element is so complex, that we can not really
13529 // use the rendered HTML.
13530 // so we have to trash and replace the previous code.
13531 if (Roo.XComponent.build_from_html) {
13532 // remove this element....
13533 var e = this.el.dom, k=0;
13534 while (e ) { e = e.previousSibling; ++k;}
13539 this.rendered = false;
13541 this.render(this.parent().getChildContainer(true), k);
13544 if(Roo.isIOS && this.useNativeIOS){
13545 this.initIOSView();
13553 if(Roo.isTouch && this.mobileTouchView){
13554 this.initTouchView();
13559 this.initTickableEvents();
13563 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13565 if(this.hiddenName){
13567 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13569 this.hiddenField.dom.value =
13570 this.hiddenValue !== undefined ? this.hiddenValue :
13571 this.value !== undefined ? this.value : '';
13573 // prevent input submission
13574 this.el.dom.removeAttribute('name');
13575 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13580 // this.el.dom.setAttribute('autocomplete', 'off');
13583 var cls = 'x-combo-list';
13585 //this.list = new Roo.Layer({
13586 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13592 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13593 _this.list.setWidth(lw);
13596 this.list.on('mouseover', this.onViewOver, this);
13597 this.list.on('mousemove', this.onViewMove, this);
13598 this.list.on('scroll', this.onViewScroll, this);
13601 this.list.swallowEvent('mousewheel');
13602 this.assetHeight = 0;
13605 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13606 this.assetHeight += this.header.getHeight();
13609 this.innerList = this.list.createChild({cls:cls+'-inner'});
13610 this.innerList.on('mouseover', this.onViewOver, this);
13611 this.innerList.on('mousemove', this.onViewMove, this);
13612 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13614 if(this.allowBlank && !this.pageSize && !this.disableClear){
13615 this.footer = this.list.createChild({cls:cls+'-ft'});
13616 this.pageTb = new Roo.Toolbar(this.footer);
13620 this.footer = this.list.createChild({cls:cls+'-ft'});
13621 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13622 {pageSize: this.pageSize});
13626 if (this.pageTb && this.allowBlank && !this.disableClear) {
13628 this.pageTb.add(new Roo.Toolbar.Fill(), {
13629 cls: 'x-btn-icon x-btn-clear',
13631 handler: function()
13634 _this.clearValue();
13635 _this.onSelect(false, -1);
13640 this.assetHeight += this.footer.getHeight();
13645 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13648 this.view = new Roo.View(this.list, this.tpl, {
13649 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13651 //this.view.wrapEl.setDisplayed(false);
13652 this.view.on('click', this.onViewClick, this);
13655 this.store.on('beforeload', this.onBeforeLoad, this);
13656 this.store.on('load', this.onLoad, this);
13657 this.store.on('loadexception', this.onLoadException, this);
13659 if(this.resizable){
13660 this.resizer = new Roo.Resizable(this.list, {
13661 pinned:true, handles:'se'
13663 this.resizer.on('resize', function(r, w, h){
13664 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13665 this.listWidth = w;
13666 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13667 this.restrictHeight();
13669 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13672 if(!this.editable){
13673 this.editable = true;
13674 this.setEditable(false);
13679 if (typeof(this.events.add.listeners) != 'undefined') {
13681 this.addicon = this.wrap.createChild(
13682 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13684 this.addicon.on('click', function(e) {
13685 this.fireEvent('add', this);
13688 if (typeof(this.events.edit.listeners) != 'undefined') {
13690 this.editicon = this.wrap.createChild(
13691 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13692 if (this.addicon) {
13693 this.editicon.setStyle('margin-left', '40px');
13695 this.editicon.on('click', function(e) {
13697 // we fire even if inothing is selected..
13698 this.fireEvent('edit', this, this.lastData );
13704 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13705 "up" : function(e){
13706 this.inKeyMode = true;
13710 "down" : function(e){
13711 if(!this.isExpanded()){
13712 this.onTriggerClick();
13714 this.inKeyMode = true;
13719 "enter" : function(e){
13720 // this.onViewClick();
13724 if(this.fireEvent("specialkey", this, e)){
13725 this.onViewClick(false);
13731 "esc" : function(e){
13735 "tab" : function(e){
13738 if(this.fireEvent("specialkey", this, e)){
13739 this.onViewClick(false);
13747 doRelay : function(foo, bar, hname){
13748 if(hname == 'down' || this.scope.isExpanded()){
13749 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13758 this.queryDelay = Math.max(this.queryDelay || 10,
13759 this.mode == 'local' ? 10 : 250);
13762 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13764 if(this.typeAhead){
13765 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13767 if(this.editable !== false){
13768 this.inputEl().on("keyup", this.onKeyUp, this);
13770 if(this.forceSelection){
13771 this.inputEl().on('blur', this.doForce, this);
13775 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13776 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13780 initTickableEvents: function()
13784 if(this.hiddenName){
13786 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13788 this.hiddenField.dom.value =
13789 this.hiddenValue !== undefined ? this.hiddenValue :
13790 this.value !== undefined ? this.value : '';
13792 // prevent input submission
13793 this.el.dom.removeAttribute('name');
13794 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13799 // this.list = this.el.select('ul.dropdown-menu',true).first();
13801 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13802 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13803 if(this.triggerList){
13804 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13807 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13808 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13810 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13811 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13813 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13814 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13816 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13817 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13818 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13821 this.cancelBtn.hide();
13826 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13827 _this.list.setWidth(lw);
13830 this.list.on('mouseover', this.onViewOver, this);
13831 this.list.on('mousemove', this.onViewMove, this);
13833 this.list.on('scroll', this.onViewScroll, this);
13836 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13837 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13840 this.view = new Roo.View(this.list, this.tpl, {
13845 selectedClass: this.selectedClass
13848 //this.view.wrapEl.setDisplayed(false);
13849 this.view.on('click', this.onViewClick, this);
13853 this.store.on('beforeload', this.onBeforeLoad, this);
13854 this.store.on('load', this.onLoad, this);
13855 this.store.on('loadexception', this.onLoadException, this);
13858 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13859 "up" : function(e){
13860 this.inKeyMode = true;
13864 "down" : function(e){
13865 this.inKeyMode = true;
13869 "enter" : function(e){
13870 if(this.fireEvent("specialkey", this, e)){
13871 this.onViewClick(false);
13877 "esc" : function(e){
13878 this.onTickableFooterButtonClick(e, false, false);
13881 "tab" : function(e){
13882 this.fireEvent("specialkey", this, e);
13884 this.onTickableFooterButtonClick(e, false, false);
13891 doRelay : function(e, fn, key){
13892 if(this.scope.isExpanded()){
13893 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13902 this.queryDelay = Math.max(this.queryDelay || 10,
13903 this.mode == 'local' ? 10 : 250);
13906 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13908 if(this.typeAhead){
13909 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13912 if(this.editable !== false){
13913 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13916 this.indicator = this.indicatorEl();
13918 if(this.indicator){
13919 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13920 this.indicator.hide();
13925 onDestroy : function(){
13927 this.view.setStore(null);
13928 this.view.el.removeAllListeners();
13929 this.view.el.remove();
13930 this.view.purgeListeners();
13933 this.list.dom.innerHTML = '';
13937 this.store.un('beforeload', this.onBeforeLoad, this);
13938 this.store.un('load', this.onLoad, this);
13939 this.store.un('loadexception', this.onLoadException, this);
13941 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13945 fireKey : function(e){
13946 if(e.isNavKeyPress() && !this.list.isVisible()){
13947 this.fireEvent("specialkey", this, e);
13952 onResize: function(w, h){
13953 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13955 // if(typeof w != 'number'){
13956 // // we do not handle it!?!?
13959 // var tw = this.trigger.getWidth();
13960 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13961 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13963 // this.inputEl().setWidth( this.adjustWidth('input', x));
13965 // //this.trigger.setStyle('left', x+'px');
13967 // if(this.list && this.listWidth === undefined){
13968 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13969 // this.list.setWidth(lw);
13970 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13978 * Allow or prevent the user from directly editing the field text. If false is passed,
13979 * the user will only be able to select from the items defined in the dropdown list. This method
13980 * is the runtime equivalent of setting the 'editable' config option at config time.
13981 * @param {Boolean} value True to allow the user to directly edit the field text
13983 setEditable : function(value){
13984 if(value == this.editable){
13987 this.editable = value;
13989 this.inputEl().dom.setAttribute('readOnly', true);
13990 this.inputEl().on('mousedown', this.onTriggerClick, this);
13991 this.inputEl().addClass('x-combo-noedit');
13993 this.inputEl().dom.setAttribute('readOnly', false);
13994 this.inputEl().un('mousedown', this.onTriggerClick, this);
13995 this.inputEl().removeClass('x-combo-noedit');
14001 onBeforeLoad : function(combo,opts){
14002 if(!this.hasFocus){
14006 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14008 this.restrictHeight();
14009 this.selectedIndex = -1;
14013 onLoad : function(){
14015 this.hasQuery = false;
14017 if(!this.hasFocus){
14021 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14022 this.loading.hide();
14025 if(this.store.getCount() > 0){
14028 this.restrictHeight();
14029 if(this.lastQuery == this.allQuery){
14030 if(this.editable && !this.tickable){
14031 this.inputEl().dom.select();
14035 !this.selectByValue(this.value, true) &&
14038 !this.store.lastOptions ||
14039 typeof(this.store.lastOptions.add) == 'undefined' ||
14040 this.store.lastOptions.add != true
14043 this.select(0, true);
14046 if(this.autoFocus){
14049 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14050 this.taTask.delay(this.typeAheadDelay);
14054 this.onEmptyResults();
14060 onLoadException : function()
14062 this.hasQuery = false;
14064 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14065 this.loading.hide();
14068 if(this.tickable && this.editable){
14073 // only causes errors at present
14074 //Roo.log(this.store.reader.jsonData);
14075 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14077 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14083 onTypeAhead : function(){
14084 if(this.store.getCount() > 0){
14085 var r = this.store.getAt(0);
14086 var newValue = r.data[this.displayField];
14087 var len = newValue.length;
14088 var selStart = this.getRawValue().length;
14090 if(selStart != len){
14091 this.setRawValue(newValue);
14092 this.selectText(selStart, newValue.length);
14098 onSelect : function(record, index){
14100 if(this.fireEvent('beforeselect', this, record, index) !== false){
14102 this.setFromData(index > -1 ? record.data : false);
14105 this.fireEvent('select', this, record, index);
14110 * Returns the currently selected field value or empty string if no value is set.
14111 * @return {String} value The selected value
14113 getValue : function()
14115 if(Roo.isIOS && this.useNativeIOS){
14116 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14120 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14123 if(this.valueField){
14124 return typeof this.value != 'undefined' ? this.value : '';
14126 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14130 getRawValue : function()
14132 if(Roo.isIOS && this.useNativeIOS){
14133 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14136 var v = this.inputEl().getValue();
14142 * Clears any text/value currently set in the field
14144 clearValue : function(){
14146 if(this.hiddenField){
14147 this.hiddenField.dom.value = '';
14150 this.setRawValue('');
14151 this.lastSelectionText = '';
14152 this.lastData = false;
14154 var close = this.closeTriggerEl();
14165 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14166 * will be displayed in the field. If the value does not match the data value of an existing item,
14167 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14168 * Otherwise the field will be blank (although the value will still be set).
14169 * @param {String} value The value to match
14171 setValue : function(v)
14173 if(Roo.isIOS && this.useNativeIOS){
14174 this.setIOSValue(v);
14184 if(this.valueField){
14185 var r = this.findRecord(this.valueField, v);
14187 text = r.data[this.displayField];
14188 }else if(this.valueNotFoundText !== undefined){
14189 text = this.valueNotFoundText;
14192 this.lastSelectionText = text;
14193 if(this.hiddenField){
14194 this.hiddenField.dom.value = v;
14196 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14199 var close = this.closeTriggerEl();
14202 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14208 * @property {Object} the last set data for the element
14213 * Sets the value of the field based on a object which is related to the record format for the store.
14214 * @param {Object} value the value to set as. or false on reset?
14216 setFromData : function(o){
14223 var dv = ''; // display value
14224 var vv = ''; // value value..
14226 if (this.displayField) {
14227 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14229 // this is an error condition!!!
14230 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14233 if(this.valueField){
14234 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14237 var close = this.closeTriggerEl();
14240 if(dv.length || vv * 1 > 0){
14242 this.blockFocus=true;
14248 if(this.hiddenField){
14249 this.hiddenField.dom.value = vv;
14251 this.lastSelectionText = dv;
14252 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14256 // no hidden field.. - we store the value in 'value', but still display
14257 // display field!!!!
14258 this.lastSelectionText = dv;
14259 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14266 reset : function(){
14267 // overridden so that last data is reset..
14274 this.setValue(this.originalValue);
14275 //this.clearInvalid();
14276 this.lastData = false;
14278 this.view.clearSelections();
14284 findRecord : function(prop, value){
14286 if(this.store.getCount() > 0){
14287 this.store.each(function(r){
14288 if(r.data[prop] == value){
14298 getName: function()
14300 // returns hidden if it's set..
14301 if (!this.rendered) {return ''};
14302 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14306 onViewMove : function(e, t){
14307 this.inKeyMode = false;
14311 onViewOver : function(e, t){
14312 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14315 var item = this.view.findItemFromChild(t);
14318 var index = this.view.indexOf(item);
14319 this.select(index, false);
14324 onViewClick : function(view, doFocus, el, e)
14326 var index = this.view.getSelectedIndexes()[0];
14328 var r = this.store.getAt(index);
14332 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14339 Roo.each(this.tickItems, function(v,k){
14341 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14343 _this.tickItems.splice(k, 1);
14345 if(typeof(e) == 'undefined' && view == false){
14346 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14358 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14359 this.tickItems.push(r.data);
14362 if(typeof(e) == 'undefined' && view == false){
14363 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14370 this.onSelect(r, index);
14372 if(doFocus !== false && !this.blockFocus){
14373 this.inputEl().focus();
14378 restrictHeight : function(){
14379 //this.innerList.dom.style.height = '';
14380 //var inner = this.innerList.dom;
14381 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14382 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14383 //this.list.beginUpdate();
14384 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14385 this.list.alignTo(this.inputEl(), this.listAlign);
14386 this.list.alignTo(this.inputEl(), this.listAlign);
14387 //this.list.endUpdate();
14391 onEmptyResults : function(){
14393 if(this.tickable && this.editable){
14394 this.hasFocus = false;
14395 this.restrictHeight();
14403 * Returns true if the dropdown list is expanded, else false.
14405 isExpanded : function(){
14406 return this.list.isVisible();
14410 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14411 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14412 * @param {String} value The data value of the item to select
14413 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14414 * selected item if it is not currently in view (defaults to true)
14415 * @return {Boolean} True if the value matched an item in the list, else false
14417 selectByValue : function(v, scrollIntoView){
14418 if(v !== undefined && v !== null){
14419 var r = this.findRecord(this.valueField || this.displayField, v);
14421 this.select(this.store.indexOf(r), scrollIntoView);
14429 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14430 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14431 * @param {Number} index The zero-based index of the list item to select
14432 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14433 * selected item if it is not currently in view (defaults to true)
14435 select : function(index, scrollIntoView){
14436 this.selectedIndex = index;
14437 this.view.select(index);
14438 if(scrollIntoView !== false){
14439 var el = this.view.getNode(index);
14441 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14444 this.list.scrollChildIntoView(el, false);
14450 selectNext : function(){
14451 var ct = this.store.getCount();
14453 if(this.selectedIndex == -1){
14455 }else if(this.selectedIndex < ct-1){
14456 this.select(this.selectedIndex+1);
14462 selectPrev : function(){
14463 var ct = this.store.getCount();
14465 if(this.selectedIndex == -1){
14467 }else if(this.selectedIndex != 0){
14468 this.select(this.selectedIndex-1);
14474 onKeyUp : function(e){
14475 if(this.editable !== false && !e.isSpecialKey()){
14476 this.lastKey = e.getKey();
14477 this.dqTask.delay(this.queryDelay);
14482 validateBlur : function(){
14483 return !this.list || !this.list.isVisible();
14487 initQuery : function(){
14489 var v = this.getRawValue();
14491 if(this.tickable && this.editable){
14492 v = this.tickableInputEl().getValue();
14499 doForce : function(){
14500 if(this.inputEl().dom.value.length > 0){
14501 this.inputEl().dom.value =
14502 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14508 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14509 * query allowing the query action to be canceled if needed.
14510 * @param {String} query The SQL query to execute
14511 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14512 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14513 * saved in the current store (defaults to false)
14515 doQuery : function(q, forceAll){
14517 if(q === undefined || q === null){
14522 forceAll: forceAll,
14526 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14531 forceAll = qe.forceAll;
14532 if(forceAll === true || (q.length >= this.minChars)){
14534 this.hasQuery = true;
14536 if(this.lastQuery != q || this.alwaysQuery){
14537 this.lastQuery = q;
14538 if(this.mode == 'local'){
14539 this.selectedIndex = -1;
14541 this.store.clearFilter();
14544 if(this.specialFilter){
14545 this.fireEvent('specialfilter', this);
14550 this.store.filter(this.displayField, q);
14553 this.store.fireEvent("datachanged", this.store);
14560 this.store.baseParams[this.queryParam] = q;
14562 var options = {params : this.getParams(q)};
14565 options.add = true;
14566 options.params.start = this.page * this.pageSize;
14569 this.store.load(options);
14572 * this code will make the page width larger, at the beginning, the list not align correctly,
14573 * we should expand the list on onLoad
14574 * so command out it
14579 this.selectedIndex = -1;
14584 this.loadNext = false;
14588 getParams : function(q){
14590 //p[this.queryParam] = q;
14594 p.limit = this.pageSize;
14600 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14602 collapse : function(){
14603 if(!this.isExpanded()){
14609 this.hasFocus = false;
14613 this.cancelBtn.hide();
14614 this.trigger.show();
14617 this.tickableInputEl().dom.value = '';
14618 this.tickableInputEl().blur();
14623 Roo.get(document).un('mousedown', this.collapseIf, this);
14624 Roo.get(document).un('mousewheel', this.collapseIf, this);
14625 if (!this.editable) {
14626 Roo.get(document).un('keydown', this.listKeyPress, this);
14628 this.fireEvent('collapse', this);
14634 collapseIf : function(e){
14635 var in_combo = e.within(this.el);
14636 var in_list = e.within(this.list);
14637 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14639 if (in_combo || in_list || is_list) {
14640 //e.stopPropagation();
14645 this.onTickableFooterButtonClick(e, false, false);
14653 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14655 expand : function(){
14657 if(this.isExpanded() || !this.hasFocus){
14661 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14662 this.list.setWidth(lw);
14668 this.restrictHeight();
14672 this.tickItems = Roo.apply([], this.item);
14675 this.cancelBtn.show();
14676 this.trigger.hide();
14679 this.tickableInputEl().focus();
14684 Roo.get(document).on('mousedown', this.collapseIf, this);
14685 Roo.get(document).on('mousewheel', this.collapseIf, this);
14686 if (!this.editable) {
14687 Roo.get(document).on('keydown', this.listKeyPress, this);
14690 this.fireEvent('expand', this);
14694 // Implements the default empty TriggerField.onTriggerClick function
14695 onTriggerClick : function(e)
14697 Roo.log('trigger click');
14699 if(this.disabled || !this.triggerList){
14704 this.loadNext = false;
14706 if(this.isExpanded()){
14708 if (!this.blockFocus) {
14709 this.inputEl().focus();
14713 this.hasFocus = true;
14714 if(this.triggerAction == 'all') {
14715 this.doQuery(this.allQuery, true);
14717 this.doQuery(this.getRawValue());
14719 if (!this.blockFocus) {
14720 this.inputEl().focus();
14725 onTickableTriggerClick : function(e)
14732 this.loadNext = false;
14733 this.hasFocus = true;
14735 if(this.triggerAction == 'all') {
14736 this.doQuery(this.allQuery, true);
14738 this.doQuery(this.getRawValue());
14742 onSearchFieldClick : function(e)
14744 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14745 this.onTickableFooterButtonClick(e, false, false);
14749 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14754 this.loadNext = false;
14755 this.hasFocus = true;
14757 if(this.triggerAction == 'all') {
14758 this.doQuery(this.allQuery, true);
14760 this.doQuery(this.getRawValue());
14764 listKeyPress : function(e)
14766 //Roo.log('listkeypress');
14767 // scroll to first matching element based on key pres..
14768 if (e.isSpecialKey()) {
14771 var k = String.fromCharCode(e.getKey()).toUpperCase();
14774 var csel = this.view.getSelectedNodes();
14775 var cselitem = false;
14777 var ix = this.view.indexOf(csel[0]);
14778 cselitem = this.store.getAt(ix);
14779 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14785 this.store.each(function(v) {
14787 // start at existing selection.
14788 if (cselitem.id == v.id) {
14794 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14795 match = this.store.indexOf(v);
14801 if (match === false) {
14802 return true; // no more action?
14805 this.view.select(match);
14806 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14807 sn.scrollIntoView(sn.dom.parentNode, false);
14810 onViewScroll : function(e, t){
14812 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){
14816 this.hasQuery = true;
14818 this.loading = this.list.select('.loading', true).first();
14820 if(this.loading === null){
14821 this.list.createChild({
14823 cls: 'loading roo-select2-more-results roo-select2-active',
14824 html: 'Loading more results...'
14827 this.loading = this.list.select('.loading', true).first();
14829 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14831 this.loading.hide();
14834 this.loading.show();
14839 this.loadNext = true;
14841 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14846 addItem : function(o)
14848 var dv = ''; // display value
14850 if (this.displayField) {
14851 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14853 // this is an error condition!!!
14854 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14861 var choice = this.choices.createChild({
14863 cls: 'roo-select2-search-choice',
14872 cls: 'roo-select2-search-choice-close fa fa-times',
14877 }, this.searchField);
14879 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14881 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14889 this.inputEl().dom.value = '';
14894 onRemoveItem : function(e, _self, o)
14896 e.preventDefault();
14898 this.lastItem = Roo.apply([], this.item);
14900 var index = this.item.indexOf(o.data) * 1;
14903 Roo.log('not this item?!');
14907 this.item.splice(index, 1);
14912 this.fireEvent('remove', this, e);
14918 syncValue : function()
14920 if(!this.item.length){
14927 Roo.each(this.item, function(i){
14928 if(_this.valueField){
14929 value.push(i[_this.valueField]);
14936 this.value = value.join(',');
14938 if(this.hiddenField){
14939 this.hiddenField.dom.value = this.value;
14942 this.store.fireEvent("datachanged", this.store);
14947 clearItem : function()
14949 if(!this.multiple){
14955 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14963 if(this.tickable && !Roo.isTouch){
14964 this.view.refresh();
14968 inputEl: function ()
14970 if(Roo.isIOS && this.useNativeIOS){
14971 return this.el.select('select.roo-ios-select', true).first();
14974 if(Roo.isTouch && this.mobileTouchView){
14975 return this.el.select('input.form-control',true).first();
14979 return this.searchField;
14982 return this.el.select('input.form-control',true).first();
14985 onTickableFooterButtonClick : function(e, btn, el)
14987 e.preventDefault();
14989 this.lastItem = Roo.apply([], this.item);
14991 if(btn && btn.name == 'cancel'){
14992 this.tickItems = Roo.apply([], this.item);
15001 Roo.each(this.tickItems, function(o){
15009 validate : function()
15011 if(this.getVisibilityEl().hasClass('hidden')){
15015 var v = this.getRawValue();
15018 v = this.getValue();
15021 if(this.disabled || this.allowBlank || v.length){
15026 this.markInvalid();
15030 tickableInputEl : function()
15032 if(!this.tickable || !this.editable){
15033 return this.inputEl();
15036 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15040 getAutoCreateTouchView : function()
15045 cls: 'form-group' //input-group
15051 type : this.inputType,
15052 cls : 'form-control x-combo-noedit',
15053 autocomplete: 'new-password',
15054 placeholder : this.placeholder || '',
15059 input.name = this.name;
15063 input.cls += ' input-' + this.size;
15066 if (this.disabled) {
15067 input.disabled = true;
15078 inputblock.cls += ' input-group';
15080 inputblock.cn.unshift({
15082 cls : 'input-group-addon input-group-prepend input-group-text',
15087 if(this.removable && !this.multiple){
15088 inputblock.cls += ' roo-removable';
15090 inputblock.cn.push({
15093 cls : 'roo-combo-removable-btn close'
15097 if(this.hasFeedback && !this.allowBlank){
15099 inputblock.cls += ' has-feedback';
15101 inputblock.cn.push({
15103 cls: 'glyphicon form-control-feedback'
15110 inputblock.cls += (this.before) ? '' : ' input-group';
15112 inputblock.cn.push({
15114 cls : 'input-group-addon input-group-append input-group-text',
15120 var ibwrap = inputblock;
15125 cls: 'roo-select2-choices',
15129 cls: 'roo-select2-search-field',
15142 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15147 cls: 'form-hidden-field'
15153 if(!this.multiple && this.showToggleBtn){
15160 if (this.caret != false) {
15163 cls: 'fa fa-' + this.caret
15170 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15175 cls: 'combobox-clear',
15189 combobox.cls += ' roo-select2-container-multi';
15192 var align = this.labelAlign || this.parentLabelAlign();
15194 if (align ==='left' && this.fieldLabel.length) {
15199 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15200 tooltip : 'This field is required'
15204 cls : 'control-label col-form-label',
15205 html : this.fieldLabel
15216 var labelCfg = cfg.cn[1];
15217 var contentCfg = cfg.cn[2];
15220 if(this.indicatorpos == 'right'){
15225 cls : 'control-label col-form-label',
15229 html : this.fieldLabel
15233 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15234 tooltip : 'This field is required'
15247 labelCfg = cfg.cn[0];
15248 contentCfg = cfg.cn[1];
15253 if(this.labelWidth > 12){
15254 labelCfg.style = "width: " + this.labelWidth + 'px';
15257 if(this.labelWidth < 13 && this.labelmd == 0){
15258 this.labelmd = this.labelWidth;
15261 if(this.labellg > 0){
15262 labelCfg.cls += ' col-lg-' + this.labellg;
15263 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15266 if(this.labelmd > 0){
15267 labelCfg.cls += ' col-md-' + this.labelmd;
15268 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15271 if(this.labelsm > 0){
15272 labelCfg.cls += ' col-sm-' + this.labelsm;
15273 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15276 if(this.labelxs > 0){
15277 labelCfg.cls += ' col-xs-' + this.labelxs;
15278 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15282 } else if ( this.fieldLabel.length) {
15286 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15287 tooltip : 'This field is required'
15291 cls : 'control-label',
15292 html : this.fieldLabel
15303 if(this.indicatorpos == 'right'){
15307 cls : 'control-label',
15308 html : this.fieldLabel,
15312 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15313 tooltip : 'This field is required'
15330 var settings = this;
15332 ['xs','sm','md','lg'].map(function(size){
15333 if (settings[size]) {
15334 cfg.cls += ' col-' + size + '-' + settings[size];
15341 initTouchView : function()
15343 this.renderTouchView();
15345 this.touchViewEl.on('scroll', function(){
15346 this.el.dom.scrollTop = 0;
15349 this.originalValue = this.getValue();
15351 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15353 this.inputEl().on("click", this.showTouchView, this);
15354 if (this.triggerEl) {
15355 this.triggerEl.on("click", this.showTouchView, this);
15359 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15360 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15362 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15364 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15365 this.store.on('load', this.onTouchViewLoad, this);
15366 this.store.on('loadexception', this.onTouchViewLoadException, this);
15368 if(this.hiddenName){
15370 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15372 this.hiddenField.dom.value =
15373 this.hiddenValue !== undefined ? this.hiddenValue :
15374 this.value !== undefined ? this.value : '';
15376 this.el.dom.removeAttribute('name');
15377 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15381 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15382 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15385 if(this.removable && !this.multiple){
15386 var close = this.closeTriggerEl();
15388 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15389 close.on('click', this.removeBtnClick, this, close);
15393 * fix the bug in Safari iOS8
15395 this.inputEl().on("focus", function(e){
15396 document.activeElement.blur();
15399 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15406 renderTouchView : function()
15408 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15409 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15411 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15412 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15414 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15415 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15416 this.touchViewBodyEl.setStyle('overflow', 'auto');
15418 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15419 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15421 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15422 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15426 showTouchView : function()
15432 this.touchViewHeaderEl.hide();
15434 if(this.modalTitle.length){
15435 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15436 this.touchViewHeaderEl.show();
15439 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15440 this.touchViewEl.show();
15442 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15444 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15445 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15447 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15449 if(this.modalTitle.length){
15450 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15453 this.touchViewBodyEl.setHeight(bodyHeight);
15457 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15459 this.touchViewEl.addClass('in');
15462 if(this._touchViewMask){
15463 Roo.get(document.body).addClass("x-body-masked");
15464 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15465 this._touchViewMask.setStyle('z-index', 10000);
15466 this._touchViewMask.addClass('show');
15469 this.doTouchViewQuery();
15473 hideTouchView : function()
15475 this.touchViewEl.removeClass('in');
15479 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15481 this.touchViewEl.setStyle('display', 'none');
15484 if(this._touchViewMask){
15485 this._touchViewMask.removeClass('show');
15486 Roo.get(document.body).removeClass("x-body-masked");
15490 setTouchViewValue : function()
15497 Roo.each(this.tickItems, function(o){
15502 this.hideTouchView();
15505 doTouchViewQuery : function()
15514 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15518 if(!this.alwaysQuery || this.mode == 'local'){
15519 this.onTouchViewLoad();
15526 onTouchViewBeforeLoad : function(combo,opts)
15532 onTouchViewLoad : function()
15534 if(this.store.getCount() < 1){
15535 this.onTouchViewEmptyResults();
15539 this.clearTouchView();
15541 var rawValue = this.getRawValue();
15543 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15545 this.tickItems = [];
15547 this.store.data.each(function(d, rowIndex){
15548 var row = this.touchViewListGroup.createChild(template);
15550 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15551 row.addClass(d.data.cls);
15554 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15557 html : d.data[this.displayField]
15560 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15561 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15564 row.removeClass('selected');
15565 if(!this.multiple && this.valueField &&
15566 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15569 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15570 row.addClass('selected');
15573 if(this.multiple && this.valueField &&
15574 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15578 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15579 this.tickItems.push(d.data);
15582 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15586 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15588 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15590 if(this.modalTitle.length){
15591 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15594 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15596 if(this.mobile_restrict_height && listHeight < bodyHeight){
15597 this.touchViewBodyEl.setHeight(listHeight);
15602 if(firstChecked && listHeight > bodyHeight){
15603 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15608 onTouchViewLoadException : function()
15610 this.hideTouchView();
15613 onTouchViewEmptyResults : function()
15615 this.clearTouchView();
15617 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15619 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15623 clearTouchView : function()
15625 this.touchViewListGroup.dom.innerHTML = '';
15628 onTouchViewClick : function(e, el, o)
15630 e.preventDefault();
15633 var rowIndex = o.rowIndex;
15635 var r = this.store.getAt(rowIndex);
15637 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15639 if(!this.multiple){
15640 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15641 c.dom.removeAttribute('checked');
15644 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15646 this.setFromData(r.data);
15648 var close = this.closeTriggerEl();
15654 this.hideTouchView();
15656 this.fireEvent('select', this, r, rowIndex);
15661 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15662 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15663 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15667 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15668 this.addItem(r.data);
15669 this.tickItems.push(r.data);
15673 getAutoCreateNativeIOS : function()
15676 cls: 'form-group' //input-group,
15681 cls : 'roo-ios-select'
15685 combobox.name = this.name;
15688 if (this.disabled) {
15689 combobox.disabled = true;
15692 var settings = this;
15694 ['xs','sm','md','lg'].map(function(size){
15695 if (settings[size]) {
15696 cfg.cls += ' col-' + size + '-' + settings[size];
15706 initIOSView : function()
15708 this.store.on('load', this.onIOSViewLoad, this);
15713 onIOSViewLoad : function()
15715 if(this.store.getCount() < 1){
15719 this.clearIOSView();
15721 if(this.allowBlank) {
15723 var default_text = '-- SELECT --';
15725 if(this.placeholder.length){
15726 default_text = this.placeholder;
15729 if(this.emptyTitle.length){
15730 default_text += ' - ' + this.emptyTitle + ' -';
15733 var opt = this.inputEl().createChild({
15736 html : default_text
15740 o[this.valueField] = 0;
15741 o[this.displayField] = default_text;
15743 this.ios_options.push({
15750 this.store.data.each(function(d, rowIndex){
15754 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15755 html = d.data[this.displayField];
15760 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15761 value = d.data[this.valueField];
15770 if(this.value == d.data[this.valueField]){
15771 option['selected'] = true;
15774 var opt = this.inputEl().createChild(option);
15776 this.ios_options.push({
15783 this.inputEl().on('change', function(){
15784 this.fireEvent('select', this);
15789 clearIOSView: function()
15791 this.inputEl().dom.innerHTML = '';
15793 this.ios_options = [];
15796 setIOSValue: function(v)
15800 if(!this.ios_options){
15804 Roo.each(this.ios_options, function(opts){
15806 opts.el.dom.removeAttribute('selected');
15808 if(opts.data[this.valueField] != v){
15812 opts.el.dom.setAttribute('selected', true);
15818 * @cfg {Boolean} grow
15822 * @cfg {Number} growMin
15826 * @cfg {Number} growMax
15835 Roo.apply(Roo.bootstrap.ComboBox, {
15839 cls: 'modal-header',
15861 cls: 'list-group-item',
15865 cls: 'roo-combobox-list-group-item-value'
15869 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15883 listItemCheckbox : {
15885 cls: 'list-group-item',
15889 cls: 'roo-combobox-list-group-item-value'
15893 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15909 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15914 cls: 'modal-footer',
15922 cls: 'col-xs-6 text-left',
15925 cls: 'btn btn-danger roo-touch-view-cancel',
15931 cls: 'col-xs-6 text-right',
15934 cls: 'btn btn-success roo-touch-view-ok',
15945 Roo.apply(Roo.bootstrap.ComboBox, {
15947 touchViewTemplate : {
15949 cls: 'modal fade roo-combobox-touch-view',
15953 cls: 'modal-dialog',
15954 style : 'position:fixed', // we have to fix position....
15958 cls: 'modal-content',
15960 Roo.bootstrap.ComboBox.header,
15961 Roo.bootstrap.ComboBox.body,
15962 Roo.bootstrap.ComboBox.footer
15971 * Ext JS Library 1.1.1
15972 * Copyright(c) 2006-2007, Ext JS, LLC.
15974 * Originally Released Under LGPL - original licence link has changed is not relivant.
15977 * <script type="text/javascript">
15982 * @extends Roo.util.Observable
15983 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15984 * This class also supports single and multi selection modes. <br>
15985 * Create a data model bound view:
15987 var store = new Roo.data.Store(...);
15989 var view = new Roo.View({
15991 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15993 singleSelect: true,
15994 selectedClass: "ydataview-selected",
15998 // listen for node click?
15999 view.on("click", function(vw, index, node, e){
16000 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16004 dataModel.load("foobar.xml");
16006 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16008 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16009 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16011 * Note: old style constructor is still suported (container, template, config)
16014 * Create a new View
16015 * @param {Object} config The config object
16018 Roo.View = function(config, depreciated_tpl, depreciated_config){
16020 this.parent = false;
16022 if (typeof(depreciated_tpl) == 'undefined') {
16023 // new way.. - universal constructor.
16024 Roo.apply(this, config);
16025 this.el = Roo.get(this.el);
16028 this.el = Roo.get(config);
16029 this.tpl = depreciated_tpl;
16030 Roo.apply(this, depreciated_config);
16032 this.wrapEl = this.el.wrap().wrap();
16033 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16036 if(typeof(this.tpl) == "string"){
16037 this.tpl = new Roo.Template(this.tpl);
16039 // support xtype ctors..
16040 this.tpl = new Roo.factory(this.tpl, Roo);
16044 this.tpl.compile();
16049 * @event beforeclick
16050 * Fires before a click is processed. Returns false to cancel the default action.
16051 * @param {Roo.View} this
16052 * @param {Number} index The index of the target node
16053 * @param {HTMLElement} node The target node
16054 * @param {Roo.EventObject} e The raw event object
16056 "beforeclick" : true,
16059 * Fires when a template node is clicked.
16060 * @param {Roo.View} this
16061 * @param {Number} index The index of the target node
16062 * @param {HTMLElement} node The target node
16063 * @param {Roo.EventObject} e The raw event object
16068 * Fires when a template node is double clicked.
16069 * @param {Roo.View} this
16070 * @param {Number} index The index of the target node
16071 * @param {HTMLElement} node The target node
16072 * @param {Roo.EventObject} e The raw event object
16076 * @event contextmenu
16077 * Fires when a template node is right clicked.
16078 * @param {Roo.View} this
16079 * @param {Number} index The index of the target node
16080 * @param {HTMLElement} node The target node
16081 * @param {Roo.EventObject} e The raw event object
16083 "contextmenu" : true,
16085 * @event selectionchange
16086 * Fires when the selected nodes change.
16087 * @param {Roo.View} this
16088 * @param {Array} selections Array of the selected nodes
16090 "selectionchange" : true,
16093 * @event beforeselect
16094 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16095 * @param {Roo.View} this
16096 * @param {HTMLElement} node The node to be selected
16097 * @param {Array} selections Array of currently selected nodes
16099 "beforeselect" : true,
16101 * @event preparedata
16102 * Fires on every row to render, to allow you to change the data.
16103 * @param {Roo.View} this
16104 * @param {Object} data to be rendered (change this)
16106 "preparedata" : true
16114 "click": this.onClick,
16115 "dblclick": this.onDblClick,
16116 "contextmenu": this.onContextMenu,
16120 this.selections = [];
16122 this.cmp = new Roo.CompositeElementLite([]);
16124 this.store = Roo.factory(this.store, Roo.data);
16125 this.setStore(this.store, true);
16128 if ( this.footer && this.footer.xtype) {
16130 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16132 this.footer.dataSource = this.store;
16133 this.footer.container = fctr;
16134 this.footer = Roo.factory(this.footer, Roo);
16135 fctr.insertFirst(this.el);
16137 // this is a bit insane - as the paging toolbar seems to detach the el..
16138 // dom.parentNode.parentNode.parentNode
16139 // they get detached?
16143 Roo.View.superclass.constructor.call(this);
16148 Roo.extend(Roo.View, Roo.util.Observable, {
16151 * @cfg {Roo.data.Store} store Data store to load data from.
16156 * @cfg {String|Roo.Element} el The container element.
16161 * @cfg {String|Roo.Template} tpl The template used by this View
16165 * @cfg {String} dataName the named area of the template to use as the data area
16166 * Works with domtemplates roo-name="name"
16170 * @cfg {String} selectedClass The css class to add to selected nodes
16172 selectedClass : "x-view-selected",
16174 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16179 * @cfg {String} text to display on mask (default Loading)
16183 * @cfg {Boolean} multiSelect Allow multiple selection
16185 multiSelect : false,
16187 * @cfg {Boolean} singleSelect Allow single selection
16189 singleSelect: false,
16192 * @cfg {Boolean} toggleSelect - selecting
16194 toggleSelect : false,
16197 * @cfg {Boolean} tickable - selecting
16202 * Returns the element this view is bound to.
16203 * @return {Roo.Element}
16205 getEl : function(){
16206 return this.wrapEl;
16212 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16214 refresh : function(){
16215 //Roo.log('refresh');
16218 // if we are using something like 'domtemplate', then
16219 // the what gets used is:
16220 // t.applySubtemplate(NAME, data, wrapping data..)
16221 // the outer template then get' applied with
16222 // the store 'extra data'
16223 // and the body get's added to the
16224 // roo-name="data" node?
16225 // <span class='roo-tpl-{name}'></span> ?????
16229 this.clearSelections();
16230 this.el.update("");
16232 var records = this.store.getRange();
16233 if(records.length < 1) {
16235 // is this valid?? = should it render a template??
16237 this.el.update(this.emptyText);
16241 if (this.dataName) {
16242 this.el.update(t.apply(this.store.meta)); //????
16243 el = this.el.child('.roo-tpl-' + this.dataName);
16246 for(var i = 0, len = records.length; i < len; i++){
16247 var data = this.prepareData(records[i].data, i, records[i]);
16248 this.fireEvent("preparedata", this, data, i, records[i]);
16250 var d = Roo.apply({}, data);
16253 Roo.apply(d, {'roo-id' : Roo.id()});
16257 Roo.each(this.parent.item, function(item){
16258 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16261 Roo.apply(d, {'roo-data-checked' : 'checked'});
16265 html[html.length] = Roo.util.Format.trim(
16267 t.applySubtemplate(this.dataName, d, this.store.meta) :
16274 el.update(html.join(""));
16275 this.nodes = el.dom.childNodes;
16276 this.updateIndexes(0);
16281 * Function to override to reformat the data that is sent to
16282 * the template for each node.
16283 * DEPRICATED - use the preparedata event handler.
16284 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16285 * a JSON object for an UpdateManager bound view).
16287 prepareData : function(data, index, record)
16289 this.fireEvent("preparedata", this, data, index, record);
16293 onUpdate : function(ds, record){
16294 // Roo.log('on update');
16295 this.clearSelections();
16296 var index = this.store.indexOf(record);
16297 var n = this.nodes[index];
16298 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16299 n.parentNode.removeChild(n);
16300 this.updateIndexes(index, index);
16306 onAdd : function(ds, records, index)
16308 //Roo.log(['on Add', ds, records, index] );
16309 this.clearSelections();
16310 if(this.nodes.length == 0){
16314 var n = this.nodes[index];
16315 for(var i = 0, len = records.length; i < len; i++){
16316 var d = this.prepareData(records[i].data, i, records[i]);
16318 this.tpl.insertBefore(n, d);
16321 this.tpl.append(this.el, d);
16324 this.updateIndexes(index);
16327 onRemove : function(ds, record, index){
16328 // Roo.log('onRemove');
16329 this.clearSelections();
16330 var el = this.dataName ?
16331 this.el.child('.roo-tpl-' + this.dataName) :
16334 el.dom.removeChild(this.nodes[index]);
16335 this.updateIndexes(index);
16339 * Refresh an individual node.
16340 * @param {Number} index
16342 refreshNode : function(index){
16343 this.onUpdate(this.store, this.store.getAt(index));
16346 updateIndexes : function(startIndex, endIndex){
16347 var ns = this.nodes;
16348 startIndex = startIndex || 0;
16349 endIndex = endIndex || ns.length - 1;
16350 for(var i = startIndex; i <= endIndex; i++){
16351 ns[i].nodeIndex = i;
16356 * Changes the data store this view uses and refresh the view.
16357 * @param {Store} store
16359 setStore : function(store, initial){
16360 if(!initial && this.store){
16361 this.store.un("datachanged", this.refresh);
16362 this.store.un("add", this.onAdd);
16363 this.store.un("remove", this.onRemove);
16364 this.store.un("update", this.onUpdate);
16365 this.store.un("clear", this.refresh);
16366 this.store.un("beforeload", this.onBeforeLoad);
16367 this.store.un("load", this.onLoad);
16368 this.store.un("loadexception", this.onLoad);
16372 store.on("datachanged", this.refresh, this);
16373 store.on("add", this.onAdd, this);
16374 store.on("remove", this.onRemove, this);
16375 store.on("update", this.onUpdate, this);
16376 store.on("clear", this.refresh, this);
16377 store.on("beforeload", this.onBeforeLoad, this);
16378 store.on("load", this.onLoad, this);
16379 store.on("loadexception", this.onLoad, this);
16387 * onbeforeLoad - masks the loading area.
16390 onBeforeLoad : function(store,opts)
16392 //Roo.log('onBeforeLoad');
16394 this.el.update("");
16396 this.el.mask(this.mask ? this.mask : "Loading" );
16398 onLoad : function ()
16405 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16406 * @param {HTMLElement} node
16407 * @return {HTMLElement} The template node
16409 findItemFromChild : function(node){
16410 var el = this.dataName ?
16411 this.el.child('.roo-tpl-' + this.dataName,true) :
16414 if(!node || node.parentNode == el){
16417 var p = node.parentNode;
16418 while(p && p != el){
16419 if(p.parentNode == el){
16428 onClick : function(e){
16429 var item = this.findItemFromChild(e.getTarget());
16431 var index = this.indexOf(item);
16432 if(this.onItemClick(item, index, e) !== false){
16433 this.fireEvent("click", this, index, item, e);
16436 this.clearSelections();
16441 onContextMenu : function(e){
16442 var item = this.findItemFromChild(e.getTarget());
16444 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16449 onDblClick : function(e){
16450 var item = this.findItemFromChild(e.getTarget());
16452 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16456 onItemClick : function(item, index, e)
16458 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16461 if (this.toggleSelect) {
16462 var m = this.isSelected(item) ? 'unselect' : 'select';
16465 _t[m](item, true, false);
16468 if(this.multiSelect || this.singleSelect){
16469 if(this.multiSelect && e.shiftKey && this.lastSelection){
16470 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16472 this.select(item, this.multiSelect && e.ctrlKey);
16473 this.lastSelection = item;
16476 if(!this.tickable){
16477 e.preventDefault();
16485 * Get the number of selected nodes.
16488 getSelectionCount : function(){
16489 return this.selections.length;
16493 * Get the currently selected nodes.
16494 * @return {Array} An array of HTMLElements
16496 getSelectedNodes : function(){
16497 return this.selections;
16501 * Get the indexes of the selected nodes.
16504 getSelectedIndexes : function(){
16505 var indexes = [], s = this.selections;
16506 for(var i = 0, len = s.length; i < len; i++){
16507 indexes.push(s[i].nodeIndex);
16513 * Clear all selections
16514 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16516 clearSelections : function(suppressEvent){
16517 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16518 this.cmp.elements = this.selections;
16519 this.cmp.removeClass(this.selectedClass);
16520 this.selections = [];
16521 if(!suppressEvent){
16522 this.fireEvent("selectionchange", this, this.selections);
16528 * Returns true if the passed node is selected
16529 * @param {HTMLElement/Number} node The node or node index
16530 * @return {Boolean}
16532 isSelected : function(node){
16533 var s = this.selections;
16537 node = this.getNode(node);
16538 return s.indexOf(node) !== -1;
16543 * @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
16544 * @param {Boolean} keepExisting (optional) true to keep existing selections
16545 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16547 select : function(nodeInfo, keepExisting, suppressEvent){
16548 if(nodeInfo instanceof Array){
16550 this.clearSelections(true);
16552 for(var i = 0, len = nodeInfo.length; i < len; i++){
16553 this.select(nodeInfo[i], true, true);
16557 var node = this.getNode(nodeInfo);
16558 if(!node || this.isSelected(node)){
16559 return; // already selected.
16562 this.clearSelections(true);
16565 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16566 Roo.fly(node).addClass(this.selectedClass);
16567 this.selections.push(node);
16568 if(!suppressEvent){
16569 this.fireEvent("selectionchange", this, this.selections);
16577 * @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
16578 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16579 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16581 unselect : function(nodeInfo, keepExisting, suppressEvent)
16583 if(nodeInfo instanceof Array){
16584 Roo.each(this.selections, function(s) {
16585 this.unselect(s, nodeInfo);
16589 var node = this.getNode(nodeInfo);
16590 if(!node || !this.isSelected(node)){
16591 //Roo.log("not selected");
16592 return; // not selected.
16596 Roo.each(this.selections, function(s) {
16598 Roo.fly(node).removeClass(this.selectedClass);
16605 this.selections= ns;
16606 this.fireEvent("selectionchange", this, this.selections);
16610 * Gets a template node.
16611 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16612 * @return {HTMLElement} The node or null if it wasn't found
16614 getNode : function(nodeInfo){
16615 if(typeof nodeInfo == "string"){
16616 return document.getElementById(nodeInfo);
16617 }else if(typeof nodeInfo == "number"){
16618 return this.nodes[nodeInfo];
16624 * Gets a range template nodes.
16625 * @param {Number} startIndex
16626 * @param {Number} endIndex
16627 * @return {Array} An array of nodes
16629 getNodes : function(start, end){
16630 var ns = this.nodes;
16631 start = start || 0;
16632 end = typeof end == "undefined" ? ns.length - 1 : end;
16635 for(var i = start; i <= end; i++){
16639 for(var i = start; i >= end; i--){
16647 * Finds the index of the passed node
16648 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16649 * @return {Number} The index of the node or -1
16651 indexOf : function(node){
16652 node = this.getNode(node);
16653 if(typeof node.nodeIndex == "number"){
16654 return node.nodeIndex;
16656 var ns = this.nodes;
16657 for(var i = 0, len = ns.length; i < len; i++){
16668 * based on jquery fullcalendar
16672 Roo.bootstrap = Roo.bootstrap || {};
16674 * @class Roo.bootstrap.Calendar
16675 * @extends Roo.bootstrap.Component
16676 * Bootstrap Calendar class
16677 * @cfg {Boolean} loadMask (true|false) default false
16678 * @cfg {Object} header generate the user specific header of the calendar, default false
16681 * Create a new Container
16682 * @param {Object} config The config object
16687 Roo.bootstrap.Calendar = function(config){
16688 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16692 * Fires when a date is selected
16693 * @param {DatePicker} this
16694 * @param {Date} date The selected date
16698 * @event monthchange
16699 * Fires when the displayed month changes
16700 * @param {DatePicker} this
16701 * @param {Date} date The selected month
16703 'monthchange': true,
16705 * @event evententer
16706 * Fires when mouse over an event
16707 * @param {Calendar} this
16708 * @param {event} Event
16710 'evententer': true,
16712 * @event eventleave
16713 * Fires when the mouse leaves an
16714 * @param {Calendar} this
16717 'eventleave': true,
16719 * @event eventclick
16720 * Fires when the mouse click an
16721 * @param {Calendar} this
16730 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16733 * @cfg {Number} startDay
16734 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16742 getAutoCreate : function(){
16745 var fc_button = function(name, corner, style, content ) {
16746 return Roo.apply({},{
16748 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16750 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16753 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16764 style : 'width:100%',
16771 cls : 'fc-header-left',
16773 fc_button('prev', 'left', 'arrow', '‹' ),
16774 fc_button('next', 'right', 'arrow', '›' ),
16775 { tag: 'span', cls: 'fc-header-space' },
16776 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16784 cls : 'fc-header-center',
16788 cls: 'fc-header-title',
16791 html : 'month / year'
16799 cls : 'fc-header-right',
16801 /* fc_button('month', 'left', '', 'month' ),
16802 fc_button('week', '', '', 'week' ),
16803 fc_button('day', 'right', '', 'day' )
16815 header = this.header;
16818 var cal_heads = function() {
16820 // fixme - handle this.
16822 for (var i =0; i < Date.dayNames.length; i++) {
16823 var d = Date.dayNames[i];
16826 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16827 html : d.substring(0,3)
16831 ret[0].cls += ' fc-first';
16832 ret[6].cls += ' fc-last';
16835 var cal_cell = function(n) {
16838 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16843 cls: 'fc-day-number',
16847 cls: 'fc-day-content',
16851 style: 'position: relative;' // height: 17px;
16863 var cal_rows = function() {
16866 for (var r = 0; r < 6; r++) {
16873 for (var i =0; i < Date.dayNames.length; i++) {
16874 var d = Date.dayNames[i];
16875 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16878 row.cn[0].cls+=' fc-first';
16879 row.cn[0].cn[0].style = 'min-height:90px';
16880 row.cn[6].cls+=' fc-last';
16884 ret[0].cls += ' fc-first';
16885 ret[4].cls += ' fc-prev-last';
16886 ret[5].cls += ' fc-last';
16893 cls: 'fc-border-separate',
16894 style : 'width:100%',
16902 cls : 'fc-first fc-last',
16920 cls : 'fc-content',
16921 style : "position: relative;",
16924 cls : 'fc-view fc-view-month fc-grid',
16925 style : 'position: relative',
16926 unselectable : 'on',
16929 cls : 'fc-event-container',
16930 style : 'position:absolute;z-index:8;top:0;left:0;'
16948 initEvents : function()
16951 throw "can not find store for calendar";
16957 style: "text-align:center",
16961 style: "background-color:white;width:50%;margin:250 auto",
16965 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16976 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16978 var size = this.el.select('.fc-content', true).first().getSize();
16979 this.maskEl.setSize(size.width, size.height);
16980 this.maskEl.enableDisplayMode("block");
16981 if(!this.loadMask){
16982 this.maskEl.hide();
16985 this.store = Roo.factory(this.store, Roo.data);
16986 this.store.on('load', this.onLoad, this);
16987 this.store.on('beforeload', this.onBeforeLoad, this);
16991 this.cells = this.el.select('.fc-day',true);
16992 //Roo.log(this.cells);
16993 this.textNodes = this.el.query('.fc-day-number');
16994 this.cells.addClassOnOver('fc-state-hover');
16996 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16997 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16998 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16999 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17001 this.on('monthchange', this.onMonthChange, this);
17003 this.update(new Date().clearTime());
17006 resize : function() {
17007 var sz = this.el.getSize();
17009 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17010 this.el.select('.fc-day-content div',true).setHeight(34);
17015 showPrevMonth : function(e){
17016 this.update(this.activeDate.add("mo", -1));
17018 showToday : function(e){
17019 this.update(new Date().clearTime());
17022 showNextMonth : function(e){
17023 this.update(this.activeDate.add("mo", 1));
17027 showPrevYear : function(){
17028 this.update(this.activeDate.add("y", -1));
17032 showNextYear : function(){
17033 this.update(this.activeDate.add("y", 1));
17038 update : function(date)
17040 var vd = this.activeDate;
17041 this.activeDate = date;
17042 // if(vd && this.el){
17043 // var t = date.getTime();
17044 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17045 // Roo.log('using add remove');
17047 // this.fireEvent('monthchange', this, date);
17049 // this.cells.removeClass("fc-state-highlight");
17050 // this.cells.each(function(c){
17051 // if(c.dateValue == t){
17052 // c.addClass("fc-state-highlight");
17053 // setTimeout(function(){
17054 // try{c.dom.firstChild.focus();}catch(e){}
17064 var days = date.getDaysInMonth();
17066 var firstOfMonth = date.getFirstDateOfMonth();
17067 var startingPos = firstOfMonth.getDay()-this.startDay;
17069 if(startingPos < this.startDay){
17073 var pm = date.add(Date.MONTH, -1);
17074 var prevStart = pm.getDaysInMonth()-startingPos;
17076 this.cells = this.el.select('.fc-day',true);
17077 this.textNodes = this.el.query('.fc-day-number');
17078 this.cells.addClassOnOver('fc-state-hover');
17080 var cells = this.cells.elements;
17081 var textEls = this.textNodes;
17083 Roo.each(cells, function(cell){
17084 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17087 days += startingPos;
17089 // convert everything to numbers so it's fast
17090 var day = 86400000;
17091 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17094 //Roo.log(prevStart);
17096 var today = new Date().clearTime().getTime();
17097 var sel = date.clearTime().getTime();
17098 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17099 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17100 var ddMatch = this.disabledDatesRE;
17101 var ddText = this.disabledDatesText;
17102 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17103 var ddaysText = this.disabledDaysText;
17104 var format = this.format;
17106 var setCellClass = function(cal, cell){
17110 //Roo.log('set Cell Class');
17112 var t = d.getTime();
17116 cell.dateValue = t;
17118 cell.className += " fc-today";
17119 cell.className += " fc-state-highlight";
17120 cell.title = cal.todayText;
17123 // disable highlight in other month..
17124 //cell.className += " fc-state-highlight";
17129 cell.className = " fc-state-disabled";
17130 cell.title = cal.minText;
17134 cell.className = " fc-state-disabled";
17135 cell.title = cal.maxText;
17139 if(ddays.indexOf(d.getDay()) != -1){
17140 cell.title = ddaysText;
17141 cell.className = " fc-state-disabled";
17144 if(ddMatch && format){
17145 var fvalue = d.dateFormat(format);
17146 if(ddMatch.test(fvalue)){
17147 cell.title = ddText.replace("%0", fvalue);
17148 cell.className = " fc-state-disabled";
17152 if (!cell.initialClassName) {
17153 cell.initialClassName = cell.dom.className;
17156 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17161 for(; i < startingPos; i++) {
17162 textEls[i].innerHTML = (++prevStart);
17163 d.setDate(d.getDate()+1);
17165 cells[i].className = "fc-past fc-other-month";
17166 setCellClass(this, cells[i]);
17171 for(; i < days; i++){
17172 intDay = i - startingPos + 1;
17173 textEls[i].innerHTML = (intDay);
17174 d.setDate(d.getDate()+1);
17176 cells[i].className = ''; // "x-date-active";
17177 setCellClass(this, cells[i]);
17181 for(; i < 42; i++) {
17182 textEls[i].innerHTML = (++extraDays);
17183 d.setDate(d.getDate()+1);
17185 cells[i].className = "fc-future fc-other-month";
17186 setCellClass(this, cells[i]);
17189 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17191 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17193 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17194 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17196 if(totalRows != 6){
17197 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17198 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17201 this.fireEvent('monthchange', this, date);
17205 if(!this.internalRender){
17206 var main = this.el.dom.firstChild;
17207 var w = main.offsetWidth;
17208 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17209 Roo.fly(main).setWidth(w);
17210 this.internalRender = true;
17211 // opera does not respect the auto grow header center column
17212 // then, after it gets a width opera refuses to recalculate
17213 // without a second pass
17214 if(Roo.isOpera && !this.secondPass){
17215 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17216 this.secondPass = true;
17217 this.update.defer(10, this, [date]);
17224 findCell : function(dt) {
17225 dt = dt.clearTime().getTime();
17227 this.cells.each(function(c){
17228 //Roo.log("check " +c.dateValue + '?=' + dt);
17229 if(c.dateValue == dt){
17239 findCells : function(ev) {
17240 var s = ev.start.clone().clearTime().getTime();
17242 var e= ev.end.clone().clearTime().getTime();
17245 this.cells.each(function(c){
17246 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17248 if(c.dateValue > e){
17251 if(c.dateValue < s){
17260 // findBestRow: function(cells)
17264 // for (var i =0 ; i < cells.length;i++) {
17265 // ret = Math.max(cells[i].rows || 0,ret);
17272 addItem : function(ev)
17274 // look for vertical location slot in
17275 var cells = this.findCells(ev);
17277 // ev.row = this.findBestRow(cells);
17279 // work out the location.
17283 for(var i =0; i < cells.length; i++) {
17285 cells[i].row = cells[0].row;
17288 cells[i].row = cells[i].row + 1;
17298 if (crow.start.getY() == cells[i].getY()) {
17300 crow.end = cells[i];
17317 cells[0].events.push(ev);
17319 this.calevents.push(ev);
17322 clearEvents: function() {
17324 if(!this.calevents){
17328 Roo.each(this.cells.elements, function(c){
17334 Roo.each(this.calevents, function(e) {
17335 Roo.each(e.els, function(el) {
17336 el.un('mouseenter' ,this.onEventEnter, this);
17337 el.un('mouseleave' ,this.onEventLeave, this);
17342 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17348 renderEvents: function()
17352 this.cells.each(function(c) {
17361 if(c.row != c.events.length){
17362 r = 4 - (4 - (c.row - c.events.length));
17365 c.events = ev.slice(0, r);
17366 c.more = ev.slice(r);
17368 if(c.more.length && c.more.length == 1){
17369 c.events.push(c.more.pop());
17372 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17376 this.cells.each(function(c) {
17378 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17381 for (var e = 0; e < c.events.length; e++){
17382 var ev = c.events[e];
17383 var rows = ev.rows;
17385 for(var i = 0; i < rows.length; i++) {
17387 // how many rows should it span..
17390 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17391 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17393 unselectable : "on",
17396 cls: 'fc-event-inner',
17400 // cls: 'fc-event-time',
17401 // html : cells.length > 1 ? '' : ev.time
17405 cls: 'fc-event-title',
17406 html : String.format('{0}', ev.title)
17413 cls: 'ui-resizable-handle ui-resizable-e',
17414 html : '  '
17421 cfg.cls += ' fc-event-start';
17423 if ((i+1) == rows.length) {
17424 cfg.cls += ' fc-event-end';
17427 var ctr = _this.el.select('.fc-event-container',true).first();
17428 var cg = ctr.createChild(cfg);
17430 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17431 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17433 var r = (c.more.length) ? 1 : 0;
17434 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17435 cg.setWidth(ebox.right - sbox.x -2);
17437 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17438 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17439 cg.on('click', _this.onEventClick, _this, ev);
17450 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17451 style : 'position: absolute',
17452 unselectable : "on",
17455 cls: 'fc-event-inner',
17459 cls: 'fc-event-title',
17467 cls: 'ui-resizable-handle ui-resizable-e',
17468 html : '  '
17474 var ctr = _this.el.select('.fc-event-container',true).first();
17475 var cg = ctr.createChild(cfg);
17477 var sbox = c.select('.fc-day-content',true).first().getBox();
17478 var ebox = c.select('.fc-day-content',true).first().getBox();
17480 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17481 cg.setWidth(ebox.right - sbox.x -2);
17483 cg.on('click', _this.onMoreEventClick, _this, c.more);
17493 onEventEnter: function (e, el,event,d) {
17494 this.fireEvent('evententer', this, el, event);
17497 onEventLeave: function (e, el,event,d) {
17498 this.fireEvent('eventleave', this, el, event);
17501 onEventClick: function (e, el,event,d) {
17502 this.fireEvent('eventclick', this, el, event);
17505 onMonthChange: function () {
17509 onMoreEventClick: function(e, el, more)
17513 this.calpopover.placement = 'right';
17514 this.calpopover.setTitle('More');
17516 this.calpopover.setContent('');
17518 var ctr = this.calpopover.el.select('.popover-content', true).first();
17520 Roo.each(more, function(m){
17522 cls : 'fc-event-hori fc-event-draggable',
17525 var cg = ctr.createChild(cfg);
17527 cg.on('click', _this.onEventClick, _this, m);
17530 this.calpopover.show(el);
17535 onLoad: function ()
17537 this.calevents = [];
17540 if(this.store.getCount() > 0){
17541 this.store.data.each(function(d){
17544 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17545 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17546 time : d.data.start_time,
17547 title : d.data.title,
17548 description : d.data.description,
17549 venue : d.data.venue
17554 this.renderEvents();
17556 if(this.calevents.length && this.loadMask){
17557 this.maskEl.hide();
17561 onBeforeLoad: function()
17563 this.clearEvents();
17565 this.maskEl.show();
17579 * @class Roo.bootstrap.Popover
17580 * @extends Roo.bootstrap.Component
17581 * Bootstrap Popover class
17582 * @cfg {String} html contents of the popover (or false to use children..)
17583 * @cfg {String} title of popover (or false to hide)
17584 * @cfg {String} placement how it is placed
17585 * @cfg {String} trigger click || hover (or false to trigger manually)
17586 * @cfg {String} over what (parent or false to trigger manually.)
17587 * @cfg {Number} delay - delay before showing
17590 * Create a new Popover
17591 * @param {Object} config The config object
17594 Roo.bootstrap.Popover = function(config){
17595 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17601 * After the popover show
17603 * @param {Roo.bootstrap.Popover} this
17608 * After the popover hide
17610 * @param {Roo.bootstrap.Popover} this
17616 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17618 title: 'Fill in a title',
17621 placement : 'right',
17622 trigger : 'hover', // hover
17628 can_build_overlaid : false,
17630 getChildContainer : function()
17632 return this.el.select('.popover-content',true).first();
17635 getAutoCreate : function(){
17638 cls : 'popover roo-dynamic',
17639 style: 'display:block',
17645 cls : 'popover-inner',
17649 cls: 'popover-title popover-header',
17653 cls : 'popover-content popover-body',
17664 setTitle: function(str)
17667 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17669 setContent: function(str)
17672 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17674 // as it get's added to the bottom of the page.
17675 onRender : function(ct, position)
17677 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17679 var cfg = Roo.apply({}, this.getAutoCreate());
17683 cfg.cls += ' ' + this.cls;
17686 cfg.style = this.style;
17688 //Roo.log("adding to ");
17689 this.el = Roo.get(document.body).createChild(cfg, position);
17690 // Roo.log(this.el);
17695 initEvents : function()
17697 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17698 this.el.enableDisplayMode('block');
17700 if (this.over === false) {
17703 if (this.triggers === false) {
17706 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17707 var triggers = this.trigger ? this.trigger.split(' ') : [];
17708 Roo.each(triggers, function(trigger) {
17710 if (trigger == 'click') {
17711 on_el.on('click', this.toggle, this);
17712 } else if (trigger != 'manual') {
17713 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17714 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17716 on_el.on(eventIn ,this.enter, this);
17717 on_el.on(eventOut, this.leave, this);
17728 toggle : function () {
17729 this.hoverState == 'in' ? this.leave() : this.enter();
17732 enter : function () {
17734 clearTimeout(this.timeout);
17736 this.hoverState = 'in';
17738 if (!this.delay || !this.delay.show) {
17743 this.timeout = setTimeout(function () {
17744 if (_t.hoverState == 'in') {
17747 }, this.delay.show)
17750 leave : function() {
17751 clearTimeout(this.timeout);
17753 this.hoverState = 'out';
17755 if (!this.delay || !this.delay.hide) {
17760 this.timeout = setTimeout(function () {
17761 if (_t.hoverState == 'out') {
17764 }, this.delay.hide)
17767 show : function (on_el)
17770 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17774 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17775 if (this.html !== false) {
17776 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17778 this.el.removeClass([
17779 'fade','top','bottom', 'left', 'right','in',
17780 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17782 if (!this.title.length) {
17783 this.el.select('.popover-title',true).hide();
17786 var placement = typeof this.placement == 'function' ?
17787 this.placement.call(this, this.el, on_el) :
17790 var autoToken = /\s?auto?\s?/i;
17791 var autoPlace = autoToken.test(placement);
17793 placement = placement.replace(autoToken, '') || 'top';
17797 //this.el.setXY([0,0]);
17799 this.el.dom.style.display='block';
17800 this.el.addClass(placement);
17802 //this.el.appendTo(on_el);
17804 var p = this.getPosition();
17805 var box = this.el.getBox();
17810 var align = Roo.bootstrap.Popover.alignment[placement];
17813 this.el.alignTo(on_el, align[0],align[1]);
17814 //var arrow = this.el.select('.arrow',true).first();
17815 //arrow.set(align[2],
17817 this.el.addClass('in');
17820 if (this.el.hasClass('fade')) {
17824 this.hoverState = 'in';
17826 this.fireEvent('show', this);
17831 this.el.setXY([0,0]);
17832 this.el.removeClass('in');
17834 this.hoverState = null;
17836 this.fireEvent('hide', this);
17841 Roo.bootstrap.Popover.alignment = {
17842 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17843 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17844 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17845 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17856 * @class Roo.bootstrap.Progress
17857 * @extends Roo.bootstrap.Component
17858 * Bootstrap Progress class
17859 * @cfg {Boolean} striped striped of the progress bar
17860 * @cfg {Boolean} active animated of the progress bar
17864 * Create a new Progress
17865 * @param {Object} config The config object
17868 Roo.bootstrap.Progress = function(config){
17869 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17872 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17877 getAutoCreate : function(){
17885 cfg.cls += ' progress-striped';
17889 cfg.cls += ' active';
17908 * @class Roo.bootstrap.ProgressBar
17909 * @extends Roo.bootstrap.Component
17910 * Bootstrap ProgressBar class
17911 * @cfg {Number} aria_valuenow aria-value now
17912 * @cfg {Number} aria_valuemin aria-value min
17913 * @cfg {Number} aria_valuemax aria-value max
17914 * @cfg {String} label label for the progress bar
17915 * @cfg {String} panel (success | info | warning | danger )
17916 * @cfg {String} role role of the progress bar
17917 * @cfg {String} sr_only text
17921 * Create a new ProgressBar
17922 * @param {Object} config The config object
17925 Roo.bootstrap.ProgressBar = function(config){
17926 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17929 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17933 aria_valuemax : 100,
17939 getAutoCreate : function()
17944 cls: 'progress-bar',
17945 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17957 cfg.role = this.role;
17960 if(this.aria_valuenow){
17961 cfg['aria-valuenow'] = this.aria_valuenow;
17964 if(this.aria_valuemin){
17965 cfg['aria-valuemin'] = this.aria_valuemin;
17968 if(this.aria_valuemax){
17969 cfg['aria-valuemax'] = this.aria_valuemax;
17972 if(this.label && !this.sr_only){
17973 cfg.html = this.label;
17977 cfg.cls += ' progress-bar-' + this.panel;
17983 update : function(aria_valuenow)
17985 this.aria_valuenow = aria_valuenow;
17987 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18002 * @class Roo.bootstrap.TabGroup
18003 * @extends Roo.bootstrap.Column
18004 * Bootstrap Column class
18005 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18006 * @cfg {Boolean} carousel true to make the group behave like a carousel
18007 * @cfg {Boolean} bullets show bullets for the panels
18008 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18009 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18010 * @cfg {Boolean} showarrow (true|false) show arrow default true
18013 * Create a new TabGroup
18014 * @param {Object} config The config object
18017 Roo.bootstrap.TabGroup = function(config){
18018 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18020 this.navId = Roo.id();
18023 Roo.bootstrap.TabGroup.register(this);
18027 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18030 transition : false,
18035 slideOnTouch : false,
18038 getAutoCreate : function()
18040 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18042 cfg.cls += ' tab-content';
18044 if (this.carousel) {
18045 cfg.cls += ' carousel slide';
18048 cls : 'carousel-inner',
18052 if(this.bullets && !Roo.isTouch){
18055 cls : 'carousel-bullets',
18059 if(this.bullets_cls){
18060 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18067 cfg.cn[0].cn.push(bullets);
18070 if(this.showarrow){
18071 cfg.cn[0].cn.push({
18073 class : 'carousel-arrow',
18077 class : 'carousel-prev',
18081 class : 'fa fa-chevron-left'
18087 class : 'carousel-next',
18091 class : 'fa fa-chevron-right'
18104 initEvents: function()
18106 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18107 // this.el.on("touchstart", this.onTouchStart, this);
18110 if(this.autoslide){
18113 this.slideFn = window.setInterval(function() {
18114 _this.showPanelNext();
18118 if(this.showarrow){
18119 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18120 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18126 // onTouchStart : function(e, el, o)
18128 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18132 // this.showPanelNext();
18136 getChildContainer : function()
18138 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18142 * register a Navigation item
18143 * @param {Roo.bootstrap.NavItem} the navitem to add
18145 register : function(item)
18147 this.tabs.push( item);
18148 item.navId = this.navId; // not really needed..
18153 getActivePanel : function()
18156 Roo.each(this.tabs, function(t) {
18166 getPanelByName : function(n)
18169 Roo.each(this.tabs, function(t) {
18170 if (t.tabId == n) {
18178 indexOfPanel : function(p)
18181 Roo.each(this.tabs, function(t,i) {
18182 if (t.tabId == p.tabId) {
18191 * show a specific panel
18192 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18193 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18195 showPanel : function (pan)
18197 if(this.transition || typeof(pan) == 'undefined'){
18198 Roo.log("waiting for the transitionend");
18202 if (typeof(pan) == 'number') {
18203 pan = this.tabs[pan];
18206 if (typeof(pan) == 'string') {
18207 pan = this.getPanelByName(pan);
18210 var cur = this.getActivePanel();
18213 Roo.log('pan or acitve pan is undefined');
18217 if (pan.tabId == this.getActivePanel().tabId) {
18221 if (false === cur.fireEvent('beforedeactivate')) {
18225 if(this.bullets > 0 && !Roo.isTouch){
18226 this.setActiveBullet(this.indexOfPanel(pan));
18229 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18231 this.transition = true;
18232 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18233 var lr = dir == 'next' ? 'left' : 'right';
18234 pan.el.addClass(dir); // or prev
18235 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18236 cur.el.addClass(lr); // or right
18237 pan.el.addClass(lr);
18240 cur.el.on('transitionend', function() {
18241 Roo.log("trans end?");
18243 pan.el.removeClass([lr,dir]);
18244 pan.setActive(true);
18246 cur.el.removeClass([lr]);
18247 cur.setActive(false);
18249 _this.transition = false;
18251 }, this, { single: true } );
18256 cur.setActive(false);
18257 pan.setActive(true);
18262 showPanelNext : function()
18264 var i = this.indexOfPanel(this.getActivePanel());
18266 if (i >= this.tabs.length - 1 && !this.autoslide) {
18270 if (i >= this.tabs.length - 1 && this.autoslide) {
18274 this.showPanel(this.tabs[i+1]);
18277 showPanelPrev : function()
18279 var i = this.indexOfPanel(this.getActivePanel());
18281 if (i < 1 && !this.autoslide) {
18285 if (i < 1 && this.autoslide) {
18286 i = this.tabs.length;
18289 this.showPanel(this.tabs[i-1]);
18293 addBullet: function()
18295 if(!this.bullets || Roo.isTouch){
18298 var ctr = this.el.select('.carousel-bullets',true).first();
18299 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18300 var bullet = ctr.createChild({
18301 cls : 'bullet bullet-' + i
18302 },ctr.dom.lastChild);
18307 bullet.on('click', (function(e, el, o, ii, t){
18309 e.preventDefault();
18311 this.showPanel(ii);
18313 if(this.autoslide && this.slideFn){
18314 clearInterval(this.slideFn);
18315 this.slideFn = window.setInterval(function() {
18316 _this.showPanelNext();
18320 }).createDelegate(this, [i, bullet], true));
18325 setActiveBullet : function(i)
18331 Roo.each(this.el.select('.bullet', true).elements, function(el){
18332 el.removeClass('selected');
18335 var bullet = this.el.select('.bullet-' + i, true).first();
18341 bullet.addClass('selected');
18352 Roo.apply(Roo.bootstrap.TabGroup, {
18356 * register a Navigation Group
18357 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18359 register : function(navgrp)
18361 this.groups[navgrp.navId] = navgrp;
18365 * fetch a Navigation Group based on the navigation ID
18366 * if one does not exist , it will get created.
18367 * @param {string} the navgroup to add
18368 * @returns {Roo.bootstrap.NavGroup} the navgroup
18370 get: function(navId) {
18371 if (typeof(this.groups[navId]) == 'undefined') {
18372 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18374 return this.groups[navId] ;
18389 * @class Roo.bootstrap.TabPanel
18390 * @extends Roo.bootstrap.Component
18391 * Bootstrap TabPanel class
18392 * @cfg {Boolean} active panel active
18393 * @cfg {String} html panel content
18394 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18395 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18396 * @cfg {String} href click to link..
18400 * Create a new TabPanel
18401 * @param {Object} config The config object
18404 Roo.bootstrap.TabPanel = function(config){
18405 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18409 * Fires when the active status changes
18410 * @param {Roo.bootstrap.TabPanel} this
18411 * @param {Boolean} state the new state
18416 * @event beforedeactivate
18417 * Fires before a tab is de-activated - can be used to do validation on a form.
18418 * @param {Roo.bootstrap.TabPanel} this
18419 * @return {Boolean} false if there is an error
18422 'beforedeactivate': true
18425 this.tabId = this.tabId || Roo.id();
18429 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18437 getAutoCreate : function(){
18440 // item is needed for carousel - not sure if it has any effect otherwise
18441 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18442 html: this.html || ''
18446 cfg.cls += ' active';
18450 cfg.tabId = this.tabId;
18457 initEvents: function()
18459 var p = this.parent();
18461 this.navId = this.navId || p.navId;
18463 if (typeof(this.navId) != 'undefined') {
18464 // not really needed.. but just in case.. parent should be a NavGroup.
18465 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18469 var i = tg.tabs.length - 1;
18471 if(this.active && tg.bullets > 0 && i < tg.bullets){
18472 tg.setActiveBullet(i);
18476 this.el.on('click', this.onClick, this);
18479 this.el.on("touchstart", this.onTouchStart, this);
18480 this.el.on("touchmove", this.onTouchMove, this);
18481 this.el.on("touchend", this.onTouchEnd, this);
18486 onRender : function(ct, position)
18488 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18491 setActive : function(state)
18493 Roo.log("panel - set active " + this.tabId + "=" + state);
18495 this.active = state;
18497 this.el.removeClass('active');
18499 } else if (!this.el.hasClass('active')) {
18500 this.el.addClass('active');
18503 this.fireEvent('changed', this, state);
18506 onClick : function(e)
18508 e.preventDefault();
18510 if(!this.href.length){
18514 window.location.href = this.href;
18523 onTouchStart : function(e)
18525 this.swiping = false;
18527 this.startX = e.browserEvent.touches[0].clientX;
18528 this.startY = e.browserEvent.touches[0].clientY;
18531 onTouchMove : function(e)
18533 this.swiping = true;
18535 this.endX = e.browserEvent.touches[0].clientX;
18536 this.endY = e.browserEvent.touches[0].clientY;
18539 onTouchEnd : function(e)
18546 var tabGroup = this.parent();
18548 if(this.endX > this.startX){ // swiping right
18549 tabGroup.showPanelPrev();
18553 if(this.startX > this.endX){ // swiping left
18554 tabGroup.showPanelNext();
18573 * @class Roo.bootstrap.DateField
18574 * @extends Roo.bootstrap.Input
18575 * Bootstrap DateField class
18576 * @cfg {Number} weekStart default 0
18577 * @cfg {String} viewMode default empty, (months|years)
18578 * @cfg {String} minViewMode default empty, (months|years)
18579 * @cfg {Number} startDate default -Infinity
18580 * @cfg {Number} endDate default Infinity
18581 * @cfg {Boolean} todayHighlight default false
18582 * @cfg {Boolean} todayBtn default false
18583 * @cfg {Boolean} calendarWeeks default false
18584 * @cfg {Object} daysOfWeekDisabled default empty
18585 * @cfg {Boolean} singleMode default false (true | false)
18587 * @cfg {Boolean} keyboardNavigation default true
18588 * @cfg {String} language default en
18591 * Create a new DateField
18592 * @param {Object} config The config object
18595 Roo.bootstrap.DateField = function(config){
18596 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18600 * Fires when this field show.
18601 * @param {Roo.bootstrap.DateField} this
18602 * @param {Mixed} date The date value
18607 * Fires when this field hide.
18608 * @param {Roo.bootstrap.DateField} this
18609 * @param {Mixed} date The date value
18614 * Fires when select a date.
18615 * @param {Roo.bootstrap.DateField} this
18616 * @param {Mixed} date The date value
18620 * @event beforeselect
18621 * Fires when before select a date.
18622 * @param {Roo.bootstrap.DateField} this
18623 * @param {Mixed} date The date value
18625 beforeselect : true
18629 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18632 * @cfg {String} format
18633 * The default date format string which can be overriden for localization support. The format must be
18634 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18638 * @cfg {String} altFormats
18639 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18640 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18642 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18650 todayHighlight : false,
18656 keyboardNavigation: true,
18658 calendarWeeks: false,
18660 startDate: -Infinity,
18664 daysOfWeekDisabled: [],
18668 singleMode : false,
18670 UTCDate: function()
18672 return new Date(Date.UTC.apply(Date, arguments));
18675 UTCToday: function()
18677 var today = new Date();
18678 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18681 getDate: function() {
18682 var d = this.getUTCDate();
18683 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18686 getUTCDate: function() {
18690 setDate: function(d) {
18691 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18694 setUTCDate: function(d) {
18696 this.setValue(this.formatDate(this.date));
18699 onRender: function(ct, position)
18702 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18704 this.language = this.language || 'en';
18705 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18706 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18708 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18709 this.format = this.format || 'm/d/y';
18710 this.isInline = false;
18711 this.isInput = true;
18712 this.component = this.el.select('.add-on', true).first() || false;
18713 this.component = (this.component && this.component.length === 0) ? false : this.component;
18714 this.hasInput = this.component && this.inputEl().length;
18716 if (typeof(this.minViewMode === 'string')) {
18717 switch (this.minViewMode) {
18719 this.minViewMode = 1;
18722 this.minViewMode = 2;
18725 this.minViewMode = 0;
18730 if (typeof(this.viewMode === 'string')) {
18731 switch (this.viewMode) {
18744 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18746 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18748 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18750 this.picker().on('mousedown', this.onMousedown, this);
18751 this.picker().on('click', this.onClick, this);
18753 this.picker().addClass('datepicker-dropdown');
18755 this.startViewMode = this.viewMode;
18757 if(this.singleMode){
18758 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18759 v.setVisibilityMode(Roo.Element.DISPLAY);
18763 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18764 v.setStyle('width', '189px');
18768 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18769 if(!this.calendarWeeks){
18774 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18775 v.attr('colspan', function(i, val){
18776 return parseInt(val) + 1;
18781 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18783 this.setStartDate(this.startDate);
18784 this.setEndDate(this.endDate);
18786 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18793 if(this.isInline) {
18798 picker : function()
18800 return this.pickerEl;
18801 // return this.el.select('.datepicker', true).first();
18804 fillDow: function()
18806 var dowCnt = this.weekStart;
18815 if(this.calendarWeeks){
18823 while (dowCnt < this.weekStart + 7) {
18827 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18831 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18834 fillMonths: function()
18837 var months = this.picker().select('>.datepicker-months td', true).first();
18839 months.dom.innerHTML = '';
18845 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18848 months.createChild(month);
18855 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;
18857 if (this.date < this.startDate) {
18858 this.viewDate = new Date(this.startDate);
18859 } else if (this.date > this.endDate) {
18860 this.viewDate = new Date(this.endDate);
18862 this.viewDate = new Date(this.date);
18870 var d = new Date(this.viewDate),
18871 year = d.getUTCFullYear(),
18872 month = d.getUTCMonth(),
18873 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18874 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18875 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18876 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18877 currentDate = this.date && this.date.valueOf(),
18878 today = this.UTCToday();
18880 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18882 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18884 // this.picker.select('>tfoot th.today').
18885 // .text(dates[this.language].today)
18886 // .toggle(this.todayBtn !== false);
18888 this.updateNavArrows();
18891 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18893 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18895 prevMonth.setUTCDate(day);
18897 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18899 var nextMonth = new Date(prevMonth);
18901 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18903 nextMonth = nextMonth.valueOf();
18905 var fillMonths = false;
18907 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18909 while(prevMonth.valueOf() <= nextMonth) {
18912 if (prevMonth.getUTCDay() === this.weekStart) {
18914 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18922 if(this.calendarWeeks){
18923 // ISO 8601: First week contains first thursday.
18924 // ISO also states week starts on Monday, but we can be more abstract here.
18926 // Start of current week: based on weekstart/current date
18927 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18928 // Thursday of this week
18929 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18930 // First Thursday of year, year from thursday
18931 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18932 // Calendar week: ms between thursdays, div ms per day, div 7 days
18933 calWeek = (th - yth) / 864e5 / 7 + 1;
18935 fillMonths.cn.push({
18943 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18945 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18948 if (this.todayHighlight &&
18949 prevMonth.getUTCFullYear() == today.getFullYear() &&
18950 prevMonth.getUTCMonth() == today.getMonth() &&
18951 prevMonth.getUTCDate() == today.getDate()) {
18952 clsName += ' today';
18955 if (currentDate && prevMonth.valueOf() === currentDate) {
18956 clsName += ' active';
18959 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18960 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18961 clsName += ' disabled';
18964 fillMonths.cn.push({
18966 cls: 'day ' + clsName,
18967 html: prevMonth.getDate()
18970 prevMonth.setDate(prevMonth.getDate()+1);
18973 var currentYear = this.date && this.date.getUTCFullYear();
18974 var currentMonth = this.date && this.date.getUTCMonth();
18976 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18978 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18979 v.removeClass('active');
18981 if(currentYear === year && k === currentMonth){
18982 v.addClass('active');
18985 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18986 v.addClass('disabled');
18992 year = parseInt(year/10, 10) * 10;
18994 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18996 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18999 for (var i = -1; i < 11; i++) {
19000 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19002 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19010 showMode: function(dir)
19013 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19016 Roo.each(this.picker().select('>div',true).elements, function(v){
19017 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19020 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19025 if(this.isInline) {
19029 this.picker().removeClass(['bottom', 'top']);
19031 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19033 * place to the top of element!
19037 this.picker().addClass('top');
19038 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19043 this.picker().addClass('bottom');
19045 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19048 parseDate : function(value)
19050 if(!value || value instanceof Date){
19053 var v = Date.parseDate(value, this.format);
19054 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19055 v = Date.parseDate(value, 'Y-m-d');
19057 if(!v && this.altFormats){
19058 if(!this.altFormatsArray){
19059 this.altFormatsArray = this.altFormats.split("|");
19061 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19062 v = Date.parseDate(value, this.altFormatsArray[i]);
19068 formatDate : function(date, fmt)
19070 return (!date || !(date instanceof Date)) ?
19071 date : date.dateFormat(fmt || this.format);
19074 onFocus : function()
19076 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19080 onBlur : function()
19082 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19084 var d = this.inputEl().getValue();
19091 showPopup : function()
19093 this.picker().show();
19097 this.fireEvent('showpopup', this, this.date);
19100 hidePopup : function()
19102 if(this.isInline) {
19105 this.picker().hide();
19106 this.viewMode = this.startViewMode;
19109 this.fireEvent('hidepopup', this, this.date);
19113 onMousedown: function(e)
19115 e.stopPropagation();
19116 e.preventDefault();
19121 Roo.bootstrap.DateField.superclass.keyup.call(this);
19125 setValue: function(v)
19127 if(this.fireEvent('beforeselect', this, v) !== false){
19128 var d = new Date(this.parseDate(v) ).clearTime();
19130 if(isNaN(d.getTime())){
19131 this.date = this.viewDate = '';
19132 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19136 v = this.formatDate(d);
19138 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19140 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19144 this.fireEvent('select', this, this.date);
19148 getValue: function()
19150 return this.formatDate(this.date);
19153 fireKey: function(e)
19155 if (!this.picker().isVisible()){
19156 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19162 var dateChanged = false,
19164 newDate, newViewDate;
19169 e.preventDefault();
19173 if (!this.keyboardNavigation) {
19176 dir = e.keyCode == 37 ? -1 : 1;
19179 newDate = this.moveYear(this.date, dir);
19180 newViewDate = this.moveYear(this.viewDate, dir);
19181 } else if (e.shiftKey){
19182 newDate = this.moveMonth(this.date, dir);
19183 newViewDate = this.moveMonth(this.viewDate, dir);
19185 newDate = new Date(this.date);
19186 newDate.setUTCDate(this.date.getUTCDate() + dir);
19187 newViewDate = new Date(this.viewDate);
19188 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19190 if (this.dateWithinRange(newDate)){
19191 this.date = newDate;
19192 this.viewDate = newViewDate;
19193 this.setValue(this.formatDate(this.date));
19195 e.preventDefault();
19196 dateChanged = true;
19201 if (!this.keyboardNavigation) {
19204 dir = e.keyCode == 38 ? -1 : 1;
19206 newDate = this.moveYear(this.date, dir);
19207 newViewDate = this.moveYear(this.viewDate, dir);
19208 } else if (e.shiftKey){
19209 newDate = this.moveMonth(this.date, dir);
19210 newViewDate = this.moveMonth(this.viewDate, dir);
19212 newDate = new Date(this.date);
19213 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19214 newViewDate = new Date(this.viewDate);
19215 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19217 if (this.dateWithinRange(newDate)){
19218 this.date = newDate;
19219 this.viewDate = newViewDate;
19220 this.setValue(this.formatDate(this.date));
19222 e.preventDefault();
19223 dateChanged = true;
19227 this.setValue(this.formatDate(this.date));
19229 e.preventDefault();
19232 this.setValue(this.formatDate(this.date));
19246 onClick: function(e)
19248 e.stopPropagation();
19249 e.preventDefault();
19251 var target = e.getTarget();
19253 if(target.nodeName.toLowerCase() === 'i'){
19254 target = Roo.get(target).dom.parentNode;
19257 var nodeName = target.nodeName;
19258 var className = target.className;
19259 var html = target.innerHTML;
19260 //Roo.log(nodeName);
19262 switch(nodeName.toLowerCase()) {
19264 switch(className) {
19270 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19271 switch(this.viewMode){
19273 this.viewDate = this.moveMonth(this.viewDate, dir);
19277 this.viewDate = this.moveYear(this.viewDate, dir);
19283 var date = new Date();
19284 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19286 this.setValue(this.formatDate(this.date));
19293 if (className.indexOf('disabled') < 0) {
19294 this.viewDate.setUTCDate(1);
19295 if (className.indexOf('month') > -1) {
19296 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19298 var year = parseInt(html, 10) || 0;
19299 this.viewDate.setUTCFullYear(year);
19303 if(this.singleMode){
19304 this.setValue(this.formatDate(this.viewDate));
19315 //Roo.log(className);
19316 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19317 var day = parseInt(html, 10) || 1;
19318 var year = this.viewDate.getUTCFullYear(),
19319 month = this.viewDate.getUTCMonth();
19321 if (className.indexOf('old') > -1) {
19328 } else if (className.indexOf('new') > -1) {
19336 //Roo.log([year,month,day]);
19337 this.date = this.UTCDate(year, month, day,0,0,0,0);
19338 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19340 //Roo.log(this.formatDate(this.date));
19341 this.setValue(this.formatDate(this.date));
19348 setStartDate: function(startDate)
19350 this.startDate = startDate || -Infinity;
19351 if (this.startDate !== -Infinity) {
19352 this.startDate = this.parseDate(this.startDate);
19355 this.updateNavArrows();
19358 setEndDate: function(endDate)
19360 this.endDate = endDate || Infinity;
19361 if (this.endDate !== Infinity) {
19362 this.endDate = this.parseDate(this.endDate);
19365 this.updateNavArrows();
19368 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19370 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19371 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19372 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19374 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19375 return parseInt(d, 10);
19378 this.updateNavArrows();
19381 updateNavArrows: function()
19383 if(this.singleMode){
19387 var d = new Date(this.viewDate),
19388 year = d.getUTCFullYear(),
19389 month = d.getUTCMonth();
19391 Roo.each(this.picker().select('.prev', true).elements, function(v){
19393 switch (this.viewMode) {
19396 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19402 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19409 Roo.each(this.picker().select('.next', true).elements, function(v){
19411 switch (this.viewMode) {
19414 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19420 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19428 moveMonth: function(date, dir)
19433 var new_date = new Date(date.valueOf()),
19434 day = new_date.getUTCDate(),
19435 month = new_date.getUTCMonth(),
19436 mag = Math.abs(dir),
19438 dir = dir > 0 ? 1 : -1;
19441 // If going back one month, make sure month is not current month
19442 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19444 return new_date.getUTCMonth() == month;
19446 // If going forward one month, make sure month is as expected
19447 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19449 return new_date.getUTCMonth() != new_month;
19451 new_month = month + dir;
19452 new_date.setUTCMonth(new_month);
19453 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19454 if (new_month < 0 || new_month > 11) {
19455 new_month = (new_month + 12) % 12;
19458 // For magnitudes >1, move one month at a time...
19459 for (var i=0; i<mag; i++) {
19460 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19461 new_date = this.moveMonth(new_date, dir);
19463 // ...then reset the day, keeping it in the new month
19464 new_month = new_date.getUTCMonth();
19465 new_date.setUTCDate(day);
19467 return new_month != new_date.getUTCMonth();
19470 // Common date-resetting loop -- if date is beyond end of month, make it
19473 new_date.setUTCDate(--day);
19474 new_date.setUTCMonth(new_month);
19479 moveYear: function(date, dir)
19481 return this.moveMonth(date, dir*12);
19484 dateWithinRange: function(date)
19486 return date >= this.startDate && date <= this.endDate;
19492 this.picker().remove();
19495 validateValue : function(value)
19497 if(this.getVisibilityEl().hasClass('hidden')){
19501 if(value.length < 1) {
19502 if(this.allowBlank){
19508 if(value.length < this.minLength){
19511 if(value.length > this.maxLength){
19515 var vt = Roo.form.VTypes;
19516 if(!vt[this.vtype](value, this)){
19520 if(typeof this.validator == "function"){
19521 var msg = this.validator(value);
19527 if(this.regex && !this.regex.test(value)){
19531 if(typeof(this.parseDate(value)) == 'undefined'){
19535 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19539 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19549 this.date = this.viewDate = '';
19551 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19556 Roo.apply(Roo.bootstrap.DateField, {
19567 html: '<i class="fa fa-arrow-left"/>'
19577 html: '<i class="fa fa-arrow-right"/>'
19619 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19620 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19621 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19622 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19623 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19636 navFnc: 'FullYear',
19641 navFnc: 'FullYear',
19646 Roo.apply(Roo.bootstrap.DateField, {
19650 cls: 'datepicker dropdown-menu roo-dynamic',
19654 cls: 'datepicker-days',
19658 cls: 'table-condensed',
19660 Roo.bootstrap.DateField.head,
19664 Roo.bootstrap.DateField.footer
19671 cls: 'datepicker-months',
19675 cls: 'table-condensed',
19677 Roo.bootstrap.DateField.head,
19678 Roo.bootstrap.DateField.content,
19679 Roo.bootstrap.DateField.footer
19686 cls: 'datepicker-years',
19690 cls: 'table-condensed',
19692 Roo.bootstrap.DateField.head,
19693 Roo.bootstrap.DateField.content,
19694 Roo.bootstrap.DateField.footer
19713 * @class Roo.bootstrap.TimeField
19714 * @extends Roo.bootstrap.Input
19715 * Bootstrap DateField class
19719 * Create a new TimeField
19720 * @param {Object} config The config object
19723 Roo.bootstrap.TimeField = function(config){
19724 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19728 * Fires when this field show.
19729 * @param {Roo.bootstrap.DateField} thisthis
19730 * @param {Mixed} date The date value
19735 * Fires when this field hide.
19736 * @param {Roo.bootstrap.DateField} this
19737 * @param {Mixed} date The date value
19742 * Fires when select a date.
19743 * @param {Roo.bootstrap.DateField} this
19744 * @param {Mixed} date The date value
19750 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19753 * @cfg {String} format
19754 * The default time format string which can be overriden for localization support. The format must be
19755 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19759 onRender: function(ct, position)
19762 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19764 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19766 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19768 this.pop = this.picker().select('>.datepicker-time',true).first();
19769 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19771 this.picker().on('mousedown', this.onMousedown, this);
19772 this.picker().on('click', this.onClick, this);
19774 this.picker().addClass('datepicker-dropdown');
19779 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19780 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19781 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19782 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19783 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19784 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19788 fireKey: function(e){
19789 if (!this.picker().isVisible()){
19790 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19796 e.preventDefault();
19804 this.onTogglePeriod();
19807 this.onIncrementMinutes();
19810 this.onDecrementMinutes();
19819 onClick: function(e) {
19820 e.stopPropagation();
19821 e.preventDefault();
19824 picker : function()
19826 return this.el.select('.datepicker', true).first();
19829 fillTime: function()
19831 var time = this.pop.select('tbody', true).first();
19833 time.dom.innerHTML = '';
19848 cls: 'hours-up glyphicon glyphicon-chevron-up'
19868 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19889 cls: 'timepicker-hour',
19904 cls: 'timepicker-minute',
19919 cls: 'btn btn-primary period',
19941 cls: 'hours-down glyphicon glyphicon-chevron-down'
19961 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19979 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19986 var hours = this.time.getHours();
19987 var minutes = this.time.getMinutes();
20000 hours = hours - 12;
20004 hours = '0' + hours;
20008 minutes = '0' + minutes;
20011 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20012 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20013 this.pop.select('button', true).first().dom.innerHTML = period;
20019 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20021 var cls = ['bottom'];
20023 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20030 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20035 this.picker().addClass(cls.join('-'));
20039 Roo.each(cls, function(c){
20041 _this.picker().setTop(_this.inputEl().getHeight());
20045 _this.picker().setTop(0 - _this.picker().getHeight());
20050 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20054 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20061 onFocus : function()
20063 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20067 onBlur : function()
20069 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20075 this.picker().show();
20080 this.fireEvent('show', this, this.date);
20085 this.picker().hide();
20088 this.fireEvent('hide', this, this.date);
20091 setTime : function()
20094 this.setValue(this.time.format(this.format));
20096 this.fireEvent('select', this, this.date);
20101 onMousedown: function(e){
20102 e.stopPropagation();
20103 e.preventDefault();
20106 onIncrementHours: function()
20108 Roo.log('onIncrementHours');
20109 this.time = this.time.add(Date.HOUR, 1);
20114 onDecrementHours: function()
20116 Roo.log('onDecrementHours');
20117 this.time = this.time.add(Date.HOUR, -1);
20121 onIncrementMinutes: function()
20123 Roo.log('onIncrementMinutes');
20124 this.time = this.time.add(Date.MINUTE, 1);
20128 onDecrementMinutes: function()
20130 Roo.log('onDecrementMinutes');
20131 this.time = this.time.add(Date.MINUTE, -1);
20135 onTogglePeriod: function()
20137 Roo.log('onTogglePeriod');
20138 this.time = this.time.add(Date.HOUR, 12);
20145 Roo.apply(Roo.bootstrap.TimeField, {
20175 cls: 'btn btn-info ok',
20187 Roo.apply(Roo.bootstrap.TimeField, {
20191 cls: 'datepicker dropdown-menu',
20195 cls: 'datepicker-time',
20199 cls: 'table-condensed',
20201 Roo.bootstrap.TimeField.content,
20202 Roo.bootstrap.TimeField.footer
20221 * @class Roo.bootstrap.MonthField
20222 * @extends Roo.bootstrap.Input
20223 * Bootstrap MonthField class
20225 * @cfg {String} language default en
20228 * Create a new MonthField
20229 * @param {Object} config The config object
20232 Roo.bootstrap.MonthField = function(config){
20233 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20238 * Fires when this field show.
20239 * @param {Roo.bootstrap.MonthField} this
20240 * @param {Mixed} date The date value
20245 * Fires when this field hide.
20246 * @param {Roo.bootstrap.MonthField} this
20247 * @param {Mixed} date The date value
20252 * Fires when select a date.
20253 * @param {Roo.bootstrap.MonthField} this
20254 * @param {String} oldvalue The old value
20255 * @param {String} newvalue The new value
20261 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20263 onRender: function(ct, position)
20266 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20268 this.language = this.language || 'en';
20269 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20270 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20272 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20273 this.isInline = false;
20274 this.isInput = true;
20275 this.component = this.el.select('.add-on', true).first() || false;
20276 this.component = (this.component && this.component.length === 0) ? false : this.component;
20277 this.hasInput = this.component && this.inputEL().length;
20279 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20281 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20283 this.picker().on('mousedown', this.onMousedown, this);
20284 this.picker().on('click', this.onClick, this);
20286 this.picker().addClass('datepicker-dropdown');
20288 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20289 v.setStyle('width', '189px');
20296 if(this.isInline) {
20302 setValue: function(v, suppressEvent)
20304 var o = this.getValue();
20306 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20310 if(suppressEvent !== true){
20311 this.fireEvent('select', this, o, v);
20316 getValue: function()
20321 onClick: function(e)
20323 e.stopPropagation();
20324 e.preventDefault();
20326 var target = e.getTarget();
20328 if(target.nodeName.toLowerCase() === 'i'){
20329 target = Roo.get(target).dom.parentNode;
20332 var nodeName = target.nodeName;
20333 var className = target.className;
20334 var html = target.innerHTML;
20336 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20340 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20342 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20348 picker : function()
20350 return this.pickerEl;
20353 fillMonths: function()
20356 var months = this.picker().select('>.datepicker-months td', true).first();
20358 months.dom.innerHTML = '';
20364 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20367 months.createChild(month);
20376 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20377 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20380 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20381 e.removeClass('active');
20383 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20384 e.addClass('active');
20391 if(this.isInline) {
20395 this.picker().removeClass(['bottom', 'top']);
20397 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20399 * place to the top of element!
20403 this.picker().addClass('top');
20404 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20409 this.picker().addClass('bottom');
20411 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20414 onFocus : function()
20416 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20420 onBlur : function()
20422 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20424 var d = this.inputEl().getValue();
20433 this.picker().show();
20434 this.picker().select('>.datepicker-months', true).first().show();
20438 this.fireEvent('show', this, this.date);
20443 if(this.isInline) {
20446 this.picker().hide();
20447 this.fireEvent('hide', this, this.date);
20451 onMousedown: function(e)
20453 e.stopPropagation();
20454 e.preventDefault();
20459 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20463 fireKey: function(e)
20465 if (!this.picker().isVisible()){
20466 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20477 e.preventDefault();
20481 dir = e.keyCode == 37 ? -1 : 1;
20483 this.vIndex = this.vIndex + dir;
20485 if(this.vIndex < 0){
20489 if(this.vIndex > 11){
20493 if(isNaN(this.vIndex)){
20497 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20503 dir = e.keyCode == 38 ? -1 : 1;
20505 this.vIndex = this.vIndex + dir * 4;
20507 if(this.vIndex < 0){
20511 if(this.vIndex > 11){
20515 if(isNaN(this.vIndex)){
20519 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20524 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20525 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20529 e.preventDefault();
20532 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20533 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20549 this.picker().remove();
20554 Roo.apply(Roo.bootstrap.MonthField, {
20573 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20574 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20579 Roo.apply(Roo.bootstrap.MonthField, {
20583 cls: 'datepicker dropdown-menu roo-dynamic',
20587 cls: 'datepicker-months',
20591 cls: 'table-condensed',
20593 Roo.bootstrap.DateField.content
20613 * @class Roo.bootstrap.CheckBox
20614 * @extends Roo.bootstrap.Input
20615 * Bootstrap CheckBox class
20617 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20618 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20619 * @cfg {String} boxLabel The text that appears beside the checkbox
20620 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20621 * @cfg {Boolean} checked initnal the element
20622 * @cfg {Boolean} inline inline the element (default false)
20623 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20624 * @cfg {String} tooltip label tooltip
20627 * Create a new CheckBox
20628 * @param {Object} config The config object
20631 Roo.bootstrap.CheckBox = function(config){
20632 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20637 * Fires when the element is checked or unchecked.
20638 * @param {Roo.bootstrap.CheckBox} this This input
20639 * @param {Boolean} checked The new checked value
20644 * Fires when the element is click.
20645 * @param {Roo.bootstrap.CheckBox} this This input
20652 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20654 inputType: 'checkbox',
20663 getAutoCreate : function()
20665 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20671 cfg.cls = 'form-group ' + this.inputType; //input-group
20674 cfg.cls += ' ' + this.inputType + '-inline';
20680 type : this.inputType,
20681 value : this.inputValue,
20682 cls : 'roo-' + this.inputType, //'form-box',
20683 placeholder : this.placeholder || ''
20687 if(this.inputType != 'radio'){
20691 cls : 'roo-hidden-value',
20692 value : this.checked ? this.inputValue : this.valueOff
20697 if (this.weight) { // Validity check?
20698 cfg.cls += " " + this.inputType + "-" + this.weight;
20701 if (this.disabled) {
20702 input.disabled=true;
20706 input.checked = this.checked;
20711 input.name = this.name;
20713 if(this.inputType != 'radio'){
20714 hidden.name = this.name;
20715 input.name = '_hidden_' + this.name;
20720 input.cls += ' input-' + this.size;
20725 ['xs','sm','md','lg'].map(function(size){
20726 if (settings[size]) {
20727 cfg.cls += ' col-' + size + '-' + settings[size];
20731 var inputblock = input;
20733 if (this.before || this.after) {
20736 cls : 'input-group',
20741 inputblock.cn.push({
20743 cls : 'input-group-addon',
20748 inputblock.cn.push(input);
20750 if(this.inputType != 'radio'){
20751 inputblock.cn.push(hidden);
20755 inputblock.cn.push({
20757 cls : 'input-group-addon',
20764 if (align ==='left' && this.fieldLabel.length) {
20765 // Roo.log("left and has label");
20770 cls : 'control-label',
20771 html : this.fieldLabel
20781 if(this.labelWidth > 12){
20782 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20785 if(this.labelWidth < 13 && this.labelmd == 0){
20786 this.labelmd = this.labelWidth;
20789 if(this.labellg > 0){
20790 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20791 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20794 if(this.labelmd > 0){
20795 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20796 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20799 if(this.labelsm > 0){
20800 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20801 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20804 if(this.labelxs > 0){
20805 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20806 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20809 } else if ( this.fieldLabel.length) {
20810 // Roo.log(" label");
20814 tag: this.boxLabel ? 'span' : 'label',
20816 cls: 'control-label box-input-label',
20817 //cls : 'input-group-addon',
20818 html : this.fieldLabel
20827 // Roo.log(" no label && no align");
20828 cfg.cn = [ inputblock ] ;
20834 var boxLabelCfg = {
20836 //'for': id, // box label is handled by onclick - so no for...
20838 html: this.boxLabel
20842 boxLabelCfg.tooltip = this.tooltip;
20845 cfg.cn.push(boxLabelCfg);
20848 if(this.inputType != 'radio'){
20849 cfg.cn.push(hidden);
20857 * return the real input element.
20859 inputEl: function ()
20861 return this.el.select('input.roo-' + this.inputType,true).first();
20863 hiddenEl: function ()
20865 return this.el.select('input.roo-hidden-value',true).first();
20868 labelEl: function()
20870 return this.el.select('label.control-label',true).first();
20872 /* depricated... */
20876 return this.labelEl();
20879 boxLabelEl: function()
20881 return this.el.select('label.box-label',true).first();
20884 initEvents : function()
20886 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20888 this.inputEl().on('click', this.onClick, this);
20890 if (this.boxLabel) {
20891 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20894 this.startValue = this.getValue();
20897 Roo.bootstrap.CheckBox.register(this);
20901 onClick : function(e)
20903 if(this.fireEvent('click', this, e) !== false){
20904 this.setChecked(!this.checked);
20909 setChecked : function(state,suppressEvent)
20911 this.startValue = this.getValue();
20913 if(this.inputType == 'radio'){
20915 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20916 e.dom.checked = false;
20919 this.inputEl().dom.checked = true;
20921 this.inputEl().dom.value = this.inputValue;
20923 if(suppressEvent !== true){
20924 this.fireEvent('check', this, true);
20932 this.checked = state;
20934 this.inputEl().dom.checked = state;
20937 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20939 if(suppressEvent !== true){
20940 this.fireEvent('check', this, state);
20946 getValue : function()
20948 if(this.inputType == 'radio'){
20949 return this.getGroupValue();
20952 return this.hiddenEl().dom.value;
20956 getGroupValue : function()
20958 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20962 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20965 setValue : function(v,suppressEvent)
20967 if(this.inputType == 'radio'){
20968 this.setGroupValue(v, suppressEvent);
20972 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20977 setGroupValue : function(v, suppressEvent)
20979 this.startValue = this.getValue();
20981 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20982 e.dom.checked = false;
20984 if(e.dom.value == v){
20985 e.dom.checked = true;
20989 if(suppressEvent !== true){
20990 this.fireEvent('check', this, true);
20998 validate : function()
21000 if(this.getVisibilityEl().hasClass('hidden')){
21006 (this.inputType == 'radio' && this.validateRadio()) ||
21007 (this.inputType == 'checkbox' && this.validateCheckbox())
21013 this.markInvalid();
21017 validateRadio : function()
21019 if(this.getVisibilityEl().hasClass('hidden')){
21023 if(this.allowBlank){
21029 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21030 if(!e.dom.checked){
21042 validateCheckbox : function()
21045 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21046 //return (this.getValue() == this.inputValue) ? true : false;
21049 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21057 for(var i in group){
21058 if(group[i].el.isVisible(true)){
21066 for(var i in group){
21071 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21078 * Mark this field as valid
21080 markValid : function()
21084 this.fireEvent('valid', this);
21086 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21089 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21096 if(this.inputType == 'radio'){
21097 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21098 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21099 e.findParent('.form-group', false, true).addClass(_this.validClass);
21106 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21107 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21111 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21117 for(var i in group){
21118 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21119 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21124 * Mark this field as invalid
21125 * @param {String} msg The validation message
21127 markInvalid : function(msg)
21129 if(this.allowBlank){
21135 this.fireEvent('invalid', this, msg);
21137 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21140 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21144 label.markInvalid();
21147 if(this.inputType == 'radio'){
21148 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21149 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21150 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21157 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21158 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21162 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21168 for(var i in group){
21169 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21170 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21175 clearInvalid : function()
21177 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21179 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21181 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21183 if (label && label.iconEl) {
21184 label.iconEl.removeClass(label.validClass);
21185 label.iconEl.removeClass(label.invalidClass);
21189 disable : function()
21191 if(this.inputType != 'radio'){
21192 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21199 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21200 _this.getActionEl().addClass(this.disabledClass);
21201 e.dom.disabled = true;
21205 this.disabled = true;
21206 this.fireEvent("disable", this);
21210 enable : function()
21212 if(this.inputType != 'radio'){
21213 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21220 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21221 _this.getActionEl().removeClass(this.disabledClass);
21222 e.dom.disabled = false;
21226 this.disabled = false;
21227 this.fireEvent("enable", this);
21231 setBoxLabel : function(v)
21236 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21242 Roo.apply(Roo.bootstrap.CheckBox, {
21247 * register a CheckBox Group
21248 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21250 register : function(checkbox)
21252 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21253 this.groups[checkbox.groupId] = {};
21256 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21260 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21264 * fetch a CheckBox Group based on the group ID
21265 * @param {string} the group ID
21266 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21268 get: function(groupId) {
21269 if (typeof(this.groups[groupId]) == 'undefined') {
21273 return this.groups[groupId] ;
21286 * @class Roo.bootstrap.Radio
21287 * @extends Roo.bootstrap.Component
21288 * Bootstrap Radio class
21289 * @cfg {String} boxLabel - the label associated
21290 * @cfg {String} value - the value of radio
21293 * Create a new Radio
21294 * @param {Object} config The config object
21296 Roo.bootstrap.Radio = function(config){
21297 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21301 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21307 getAutoCreate : function()
21311 cls : 'form-group radio',
21316 html : this.boxLabel
21324 initEvents : function()
21326 this.parent().register(this);
21328 this.el.on('click', this.onClick, this);
21332 onClick : function(e)
21334 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21335 this.setChecked(true);
21339 setChecked : function(state, suppressEvent)
21341 this.parent().setValue(this.value, suppressEvent);
21345 setBoxLabel : function(v)
21350 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21365 * @class Roo.bootstrap.SecurePass
21366 * @extends Roo.bootstrap.Input
21367 * Bootstrap SecurePass class
21371 * Create a new SecurePass
21372 * @param {Object} config The config object
21375 Roo.bootstrap.SecurePass = function (config) {
21376 // these go here, so the translation tool can replace them..
21378 PwdEmpty: "Please type a password, and then retype it to confirm.",
21379 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21380 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21381 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21382 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21383 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21384 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21385 TooWeak: "Your password is Too Weak."
21387 this.meterLabel = "Password strength:";
21388 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21389 this.meterClass = [
21390 "roo-password-meter-tooweak",
21391 "roo-password-meter-weak",
21392 "roo-password-meter-medium",
21393 "roo-password-meter-strong",
21394 "roo-password-meter-grey"
21399 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21402 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21404 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21406 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21407 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21408 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21409 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21410 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21411 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21412 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21422 * @cfg {String/Object} Label for the strength meter (defaults to
21423 * 'Password strength:')
21428 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21429 * ['Weak', 'Medium', 'Strong'])
21432 pwdStrengths: false,
21445 initEvents: function ()
21447 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21449 if (this.el.is('input[type=password]') && Roo.isSafari) {
21450 this.el.on('keydown', this.SafariOnKeyDown, this);
21453 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21456 onRender: function (ct, position)
21458 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21459 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21460 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21462 this.trigger.createChild({
21467 cls: 'roo-password-meter-grey col-xs-12',
21470 //width: this.meterWidth + 'px'
21474 cls: 'roo-password-meter-text'
21480 if (this.hideTrigger) {
21481 this.trigger.setDisplayed(false);
21483 this.setSize(this.width || '', this.height || '');
21486 onDestroy: function ()
21488 if (this.trigger) {
21489 this.trigger.removeAllListeners();
21490 this.trigger.remove();
21493 this.wrap.remove();
21495 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21498 checkStrength: function ()
21500 var pwd = this.inputEl().getValue();
21501 if (pwd == this._lastPwd) {
21506 if (this.ClientSideStrongPassword(pwd)) {
21508 } else if (this.ClientSideMediumPassword(pwd)) {
21510 } else if (this.ClientSideWeakPassword(pwd)) {
21516 Roo.log('strength1: ' + strength);
21518 //var pm = this.trigger.child('div/div/div').dom;
21519 var pm = this.trigger.child('div/div');
21520 pm.removeClass(this.meterClass);
21521 pm.addClass(this.meterClass[strength]);
21524 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21526 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21528 this._lastPwd = pwd;
21532 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21534 this._lastPwd = '';
21536 var pm = this.trigger.child('div/div');
21537 pm.removeClass(this.meterClass);
21538 pm.addClass('roo-password-meter-grey');
21541 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21544 this.inputEl().dom.type='password';
21547 validateValue: function (value)
21550 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21553 if (value.length == 0) {
21554 if (this.allowBlank) {
21555 this.clearInvalid();
21559 this.markInvalid(this.errors.PwdEmpty);
21560 this.errorMsg = this.errors.PwdEmpty;
21568 if ('[\x21-\x7e]*'.match(value)) {
21569 this.markInvalid(this.errors.PwdBadChar);
21570 this.errorMsg = this.errors.PwdBadChar;
21573 if (value.length < 6) {
21574 this.markInvalid(this.errors.PwdShort);
21575 this.errorMsg = this.errors.PwdShort;
21578 if (value.length > 16) {
21579 this.markInvalid(this.errors.PwdLong);
21580 this.errorMsg = this.errors.PwdLong;
21584 if (this.ClientSideStrongPassword(value)) {
21586 } else if (this.ClientSideMediumPassword(value)) {
21588 } else if (this.ClientSideWeakPassword(value)) {
21595 if (strength < 2) {
21596 //this.markInvalid(this.errors.TooWeak);
21597 this.errorMsg = this.errors.TooWeak;
21602 console.log('strength2: ' + strength);
21604 //var pm = this.trigger.child('div/div/div').dom;
21606 var pm = this.trigger.child('div/div');
21607 pm.removeClass(this.meterClass);
21608 pm.addClass(this.meterClass[strength]);
21610 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21612 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21614 this.errorMsg = '';
21618 CharacterSetChecks: function (type)
21621 this.fResult = false;
21624 isctype: function (character, type)
21627 case this.kCapitalLetter:
21628 if (character >= 'A' && character <= 'Z') {
21633 case this.kSmallLetter:
21634 if (character >= 'a' && character <= 'z') {
21640 if (character >= '0' && character <= '9') {
21645 case this.kPunctuation:
21646 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21657 IsLongEnough: function (pwd, size)
21659 return !(pwd == null || isNaN(size) || pwd.length < size);
21662 SpansEnoughCharacterSets: function (word, nb)
21664 if (!this.IsLongEnough(word, nb))
21669 var characterSetChecks = new Array(
21670 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21671 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21674 for (var index = 0; index < word.length; ++index) {
21675 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21676 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21677 characterSetChecks[nCharSet].fResult = true;
21684 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21685 if (characterSetChecks[nCharSet].fResult) {
21690 if (nCharSets < nb) {
21696 ClientSideStrongPassword: function (pwd)
21698 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21701 ClientSideMediumPassword: function (pwd)
21703 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21706 ClientSideWeakPassword: function (pwd)
21708 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21711 })//<script type="text/javascript">
21714 * Based Ext JS Library 1.1.1
21715 * Copyright(c) 2006-2007, Ext JS, LLC.
21721 * @class Roo.HtmlEditorCore
21722 * @extends Roo.Component
21723 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21725 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21728 Roo.HtmlEditorCore = function(config){
21731 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21736 * @event initialize
21737 * Fires when the editor is fully initialized (including the iframe)
21738 * @param {Roo.HtmlEditorCore} this
21743 * Fires when the editor is first receives the focus. Any insertion must wait
21744 * until after this event.
21745 * @param {Roo.HtmlEditorCore} this
21749 * @event beforesync
21750 * Fires before the textarea is updated with content from the editor iframe. Return false
21751 * to cancel the sync.
21752 * @param {Roo.HtmlEditorCore} this
21753 * @param {String} html
21757 * @event beforepush
21758 * Fires before the iframe editor is updated with content from the textarea. Return false
21759 * to cancel the push.
21760 * @param {Roo.HtmlEditorCore} this
21761 * @param {String} html
21766 * Fires when the textarea is updated with content from the editor iframe.
21767 * @param {Roo.HtmlEditorCore} this
21768 * @param {String} html
21773 * Fires when the iframe editor is updated with content from the textarea.
21774 * @param {Roo.HtmlEditorCore} this
21775 * @param {String} html
21780 * @event editorevent
21781 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21782 * @param {Roo.HtmlEditorCore} this
21788 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21790 // defaults : white / black...
21791 this.applyBlacklists();
21798 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21802 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21808 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21813 * @cfg {Number} height (in pixels)
21817 * @cfg {Number} width (in pixels)
21822 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21825 stylesheets: false,
21830 // private properties
21831 validationEvent : false,
21833 initialized : false,
21835 sourceEditMode : false,
21836 onFocus : Roo.emptyFn,
21838 hideMode:'offsets',
21842 // blacklist + whitelisted elements..
21849 * Protected method that will not generally be called directly. It
21850 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21851 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21853 getDocMarkup : function(){
21857 // inherit styels from page...??
21858 if (this.stylesheets === false) {
21860 Roo.get(document.head).select('style').each(function(node) {
21861 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21864 Roo.get(document.head).select('link').each(function(node) {
21865 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21868 } else if (!this.stylesheets.length) {
21870 st = '<style type="text/css">' +
21871 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21874 st = '<style type="text/css">' +
21879 st += '<style type="text/css">' +
21880 'IMG { cursor: pointer } ' +
21883 var cls = 'roo-htmleditor-body';
21885 if(this.bodyCls.length){
21886 cls += ' ' + this.bodyCls;
21889 return '<html><head>' + st +
21890 //<style type="text/css">' +
21891 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21893 ' </head><body class="' + cls + '"></body></html>';
21897 onRender : function(ct, position)
21900 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21901 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21904 this.el.dom.style.border = '0 none';
21905 this.el.dom.setAttribute('tabIndex', -1);
21906 this.el.addClass('x-hidden hide');
21910 if(Roo.isIE){ // fix IE 1px bogus margin
21911 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21915 this.frameId = Roo.id();
21919 var iframe = this.owner.wrap.createChild({
21921 cls: 'form-control', // bootstrap..
21923 name: this.frameId,
21924 frameBorder : 'no',
21925 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21930 this.iframe = iframe.dom;
21932 this.assignDocWin();
21934 this.doc.designMode = 'on';
21937 this.doc.write(this.getDocMarkup());
21941 var task = { // must defer to wait for browser to be ready
21943 //console.log("run task?" + this.doc.readyState);
21944 this.assignDocWin();
21945 if(this.doc.body || this.doc.readyState == 'complete'){
21947 this.doc.designMode="on";
21951 Roo.TaskMgr.stop(task);
21952 this.initEditor.defer(10, this);
21959 Roo.TaskMgr.start(task);
21964 onResize : function(w, h)
21966 Roo.log('resize: ' +w + ',' + h );
21967 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21971 if(typeof w == 'number'){
21973 this.iframe.style.width = w + 'px';
21975 if(typeof h == 'number'){
21977 this.iframe.style.height = h + 'px';
21979 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21986 * Toggles the editor between standard and source edit mode.
21987 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21989 toggleSourceEdit : function(sourceEditMode){
21991 this.sourceEditMode = sourceEditMode === true;
21993 if(this.sourceEditMode){
21995 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21998 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21999 //this.iframe.className = '';
22002 //this.setSize(this.owner.wrap.getSize());
22003 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22010 * Protected method that will not generally be called directly. If you need/want
22011 * custom HTML cleanup, this is the method you should override.
22012 * @param {String} html The HTML to be cleaned
22013 * return {String} The cleaned HTML
22015 cleanHtml : function(html){
22016 html = String(html);
22017 if(html.length > 5){
22018 if(Roo.isSafari){ // strip safari nonsense
22019 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22022 if(html == ' '){
22029 * HTML Editor -> Textarea
22030 * Protected method that will not generally be called directly. Syncs the contents
22031 * of the editor iframe with the textarea.
22033 syncValue : function(){
22034 if(this.initialized){
22035 var bd = (this.doc.body || this.doc.documentElement);
22036 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22037 var html = bd.innerHTML;
22039 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22040 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22042 html = '<div style="'+m[0]+'">' + html + '</div>';
22045 html = this.cleanHtml(html);
22046 // fix up the special chars.. normaly like back quotes in word...
22047 // however we do not want to do this with chinese..
22048 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22049 var cc = b.charCodeAt();
22051 (cc >= 0x4E00 && cc < 0xA000 ) ||
22052 (cc >= 0x3400 && cc < 0x4E00 ) ||
22053 (cc >= 0xf900 && cc < 0xfb00 )
22059 if(this.owner.fireEvent('beforesync', this, html) !== false){
22060 this.el.dom.value = html;
22061 this.owner.fireEvent('sync', this, html);
22067 * Protected method that will not generally be called directly. Pushes the value of the textarea
22068 * into the iframe editor.
22070 pushValue : function(){
22071 if(this.initialized){
22072 var v = this.el.dom.value.trim();
22074 // if(v.length < 1){
22078 if(this.owner.fireEvent('beforepush', this, v) !== false){
22079 var d = (this.doc.body || this.doc.documentElement);
22081 this.cleanUpPaste();
22082 this.el.dom.value = d.innerHTML;
22083 this.owner.fireEvent('push', this, v);
22089 deferFocus : function(){
22090 this.focus.defer(10, this);
22094 focus : function(){
22095 if(this.win && !this.sourceEditMode){
22102 assignDocWin: function()
22104 var iframe = this.iframe;
22107 this.doc = iframe.contentWindow.document;
22108 this.win = iframe.contentWindow;
22110 // if (!Roo.get(this.frameId)) {
22113 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22114 // this.win = Roo.get(this.frameId).dom.contentWindow;
22116 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22120 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22121 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22126 initEditor : function(){
22127 //console.log("INIT EDITOR");
22128 this.assignDocWin();
22132 this.doc.designMode="on";
22134 this.doc.write(this.getDocMarkup());
22137 var dbody = (this.doc.body || this.doc.documentElement);
22138 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22139 // this copies styles from the containing element into thsi one..
22140 // not sure why we need all of this..
22141 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22143 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22144 //ss['background-attachment'] = 'fixed'; // w3c
22145 dbody.bgProperties = 'fixed'; // ie
22146 //Roo.DomHelper.applyStyles(dbody, ss);
22147 Roo.EventManager.on(this.doc, {
22148 //'mousedown': this.onEditorEvent,
22149 'mouseup': this.onEditorEvent,
22150 'dblclick': this.onEditorEvent,
22151 'click': this.onEditorEvent,
22152 'keyup': this.onEditorEvent,
22157 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22159 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22160 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22162 this.initialized = true;
22164 this.owner.fireEvent('initialize', this);
22169 onDestroy : function(){
22175 //for (var i =0; i < this.toolbars.length;i++) {
22176 // // fixme - ask toolbars for heights?
22177 // this.toolbars[i].onDestroy();
22180 //this.wrap.dom.innerHTML = '';
22181 //this.wrap.remove();
22186 onFirstFocus : function(){
22188 this.assignDocWin();
22191 this.activated = true;
22194 if(Roo.isGecko){ // prevent silly gecko errors
22196 var s = this.win.getSelection();
22197 if(!s.focusNode || s.focusNode.nodeType != 3){
22198 var r = s.getRangeAt(0);
22199 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22204 this.execCmd('useCSS', true);
22205 this.execCmd('styleWithCSS', false);
22208 this.owner.fireEvent('activate', this);
22212 adjustFont: function(btn){
22213 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22214 //if(Roo.isSafari){ // safari
22217 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22218 if(Roo.isSafari){ // safari
22219 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22220 v = (v < 10) ? 10 : v;
22221 v = (v > 48) ? 48 : v;
22222 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22227 v = Math.max(1, v+adjust);
22229 this.execCmd('FontSize', v );
22232 onEditorEvent : function(e)
22234 this.owner.fireEvent('editorevent', this, e);
22235 // this.updateToolbar();
22236 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22239 insertTag : function(tg)
22241 // could be a bit smarter... -> wrap the current selected tRoo..
22242 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22244 range = this.createRange(this.getSelection());
22245 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22246 wrappingNode.appendChild(range.extractContents());
22247 range.insertNode(wrappingNode);
22254 this.execCmd("formatblock", tg);
22258 insertText : function(txt)
22262 var range = this.createRange();
22263 range.deleteContents();
22264 //alert(Sender.getAttribute('label'));
22266 range.insertNode(this.doc.createTextNode(txt));
22272 * Executes a Midas editor command on the editor document and performs necessary focus and
22273 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22274 * @param {String} cmd The Midas command
22275 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22277 relayCmd : function(cmd, value){
22279 this.execCmd(cmd, value);
22280 this.owner.fireEvent('editorevent', this);
22281 //this.updateToolbar();
22282 this.owner.deferFocus();
22286 * Executes a Midas editor command directly on the editor document.
22287 * For visual commands, you should use {@link #relayCmd} instead.
22288 * <b>This should only be called after the editor is initialized.</b>
22289 * @param {String} cmd The Midas command
22290 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22292 execCmd : function(cmd, value){
22293 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22300 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22302 * @param {String} text | dom node..
22304 insertAtCursor : function(text)
22307 if(!this.activated){
22313 var r = this.doc.selection.createRange();
22324 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22328 // from jquery ui (MIT licenced)
22330 var win = this.win;
22332 if (win.getSelection && win.getSelection().getRangeAt) {
22333 range = win.getSelection().getRangeAt(0);
22334 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22335 range.insertNode(node);
22336 } else if (win.document.selection && win.document.selection.createRange) {
22337 // no firefox support
22338 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22339 win.document.selection.createRange().pasteHTML(txt);
22341 // no firefox support
22342 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22343 this.execCmd('InsertHTML', txt);
22352 mozKeyPress : function(e){
22354 var c = e.getCharCode(), cmd;
22357 c = String.fromCharCode(c).toLowerCase();
22371 this.cleanUpPaste.defer(100, this);
22379 e.preventDefault();
22387 fixKeys : function(){ // load time branching for fastest keydown performance
22389 return function(e){
22390 var k = e.getKey(), r;
22393 r = this.doc.selection.createRange();
22396 r.pasteHTML('    ');
22403 r = this.doc.selection.createRange();
22405 var target = r.parentElement();
22406 if(!target || target.tagName.toLowerCase() != 'li'){
22408 r.pasteHTML('<br />');
22414 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22415 this.cleanUpPaste.defer(100, this);
22421 }else if(Roo.isOpera){
22422 return function(e){
22423 var k = e.getKey();
22427 this.execCmd('InsertHTML','    ');
22430 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22431 this.cleanUpPaste.defer(100, this);
22436 }else if(Roo.isSafari){
22437 return function(e){
22438 var k = e.getKey();
22442 this.execCmd('InsertText','\t');
22446 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22447 this.cleanUpPaste.defer(100, this);
22455 getAllAncestors: function()
22457 var p = this.getSelectedNode();
22460 a.push(p); // push blank onto stack..
22461 p = this.getParentElement();
22465 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22469 a.push(this.doc.body);
22473 lastSelNode : false,
22476 getSelection : function()
22478 this.assignDocWin();
22479 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22482 getSelectedNode: function()
22484 // this may only work on Gecko!!!
22486 // should we cache this!!!!
22491 var range = this.createRange(this.getSelection()).cloneRange();
22494 var parent = range.parentElement();
22496 var testRange = range.duplicate();
22497 testRange.moveToElementText(parent);
22498 if (testRange.inRange(range)) {
22501 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22504 parent = parent.parentElement;
22509 // is ancestor a text element.
22510 var ac = range.commonAncestorContainer;
22511 if (ac.nodeType == 3) {
22512 ac = ac.parentNode;
22515 var ar = ac.childNodes;
22518 var other_nodes = [];
22519 var has_other_nodes = false;
22520 for (var i=0;i<ar.length;i++) {
22521 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22524 // fullly contained node.
22526 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22531 // probably selected..
22532 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22533 other_nodes.push(ar[i]);
22537 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22542 has_other_nodes = true;
22544 if (!nodes.length && other_nodes.length) {
22545 nodes= other_nodes;
22547 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22553 createRange: function(sel)
22555 // this has strange effects when using with
22556 // top toolbar - not sure if it's a great idea.
22557 //this.editor.contentWindow.focus();
22558 if (typeof sel != "undefined") {
22560 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22562 return this.doc.createRange();
22565 return this.doc.createRange();
22568 getParentElement: function()
22571 this.assignDocWin();
22572 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22574 var range = this.createRange(sel);
22577 var p = range.commonAncestorContainer;
22578 while (p.nodeType == 3) { // text node
22589 * Range intersection.. the hard stuff...
22593 * [ -- selected range --- ]
22597 * if end is before start or hits it. fail.
22598 * if start is after end or hits it fail.
22600 * if either hits (but other is outside. - then it's not
22606 // @see http://www.thismuchiknow.co.uk/?p=64.
22607 rangeIntersectsNode : function(range, node)
22609 var nodeRange = node.ownerDocument.createRange();
22611 nodeRange.selectNode(node);
22613 nodeRange.selectNodeContents(node);
22616 var rangeStartRange = range.cloneRange();
22617 rangeStartRange.collapse(true);
22619 var rangeEndRange = range.cloneRange();
22620 rangeEndRange.collapse(false);
22622 var nodeStartRange = nodeRange.cloneRange();
22623 nodeStartRange.collapse(true);
22625 var nodeEndRange = nodeRange.cloneRange();
22626 nodeEndRange.collapse(false);
22628 return rangeStartRange.compareBoundaryPoints(
22629 Range.START_TO_START, nodeEndRange) == -1 &&
22630 rangeEndRange.compareBoundaryPoints(
22631 Range.START_TO_START, nodeStartRange) == 1;
22635 rangeCompareNode : function(range, node)
22637 var nodeRange = node.ownerDocument.createRange();
22639 nodeRange.selectNode(node);
22641 nodeRange.selectNodeContents(node);
22645 range.collapse(true);
22647 nodeRange.collapse(true);
22649 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22650 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22652 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22654 var nodeIsBefore = ss == 1;
22655 var nodeIsAfter = ee == -1;
22657 if (nodeIsBefore && nodeIsAfter) {
22660 if (!nodeIsBefore && nodeIsAfter) {
22661 return 1; //right trailed.
22664 if (nodeIsBefore && !nodeIsAfter) {
22665 return 2; // left trailed.
22671 // private? - in a new class?
22672 cleanUpPaste : function()
22674 // cleans up the whole document..
22675 Roo.log('cleanuppaste');
22677 this.cleanUpChildren(this.doc.body);
22678 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22679 if (clean != this.doc.body.innerHTML) {
22680 this.doc.body.innerHTML = clean;
22685 cleanWordChars : function(input) {// change the chars to hex code
22686 var he = Roo.HtmlEditorCore;
22688 var output = input;
22689 Roo.each(he.swapCodes, function(sw) {
22690 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22692 output = output.replace(swapper, sw[1]);
22699 cleanUpChildren : function (n)
22701 if (!n.childNodes.length) {
22704 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22705 this.cleanUpChild(n.childNodes[i]);
22712 cleanUpChild : function (node)
22715 //console.log(node);
22716 if (node.nodeName == "#text") {
22717 // clean up silly Windows -- stuff?
22720 if (node.nodeName == "#comment") {
22721 node.parentNode.removeChild(node);
22722 // clean up silly Windows -- stuff?
22725 var lcname = node.tagName.toLowerCase();
22726 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22727 // whitelist of tags..
22729 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22731 node.parentNode.removeChild(node);
22736 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22738 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22739 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22741 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22742 // remove_keep_children = true;
22745 if (remove_keep_children) {
22746 this.cleanUpChildren(node);
22747 // inserts everything just before this node...
22748 while (node.childNodes.length) {
22749 var cn = node.childNodes[0];
22750 node.removeChild(cn);
22751 node.parentNode.insertBefore(cn, node);
22753 node.parentNode.removeChild(node);
22757 if (!node.attributes || !node.attributes.length) {
22758 this.cleanUpChildren(node);
22762 function cleanAttr(n,v)
22765 if (v.match(/^\./) || v.match(/^\//)) {
22768 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22771 if (v.match(/^#/)) {
22774 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22775 node.removeAttribute(n);
22779 var cwhite = this.cwhite;
22780 var cblack = this.cblack;
22782 function cleanStyle(n,v)
22784 if (v.match(/expression/)) { //XSS?? should we even bother..
22785 node.removeAttribute(n);
22789 var parts = v.split(/;/);
22792 Roo.each(parts, function(p) {
22793 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22797 var l = p.split(':').shift().replace(/\s+/g,'');
22798 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22800 if ( cwhite.length && cblack.indexOf(l) > -1) {
22801 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22802 //node.removeAttribute(n);
22806 // only allow 'c whitelisted system attributes'
22807 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22808 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22809 //node.removeAttribute(n);
22819 if (clean.length) {
22820 node.setAttribute(n, clean.join(';'));
22822 node.removeAttribute(n);
22828 for (var i = node.attributes.length-1; i > -1 ; i--) {
22829 var a = node.attributes[i];
22832 if (a.name.toLowerCase().substr(0,2)=='on') {
22833 node.removeAttribute(a.name);
22836 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22837 node.removeAttribute(a.name);
22840 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22841 cleanAttr(a.name,a.value); // fixme..
22844 if (a.name == 'style') {
22845 cleanStyle(a.name,a.value);
22848 /// clean up MS crap..
22849 // tecnically this should be a list of valid class'es..
22852 if (a.name == 'class') {
22853 if (a.value.match(/^Mso/)) {
22854 node.className = '';
22857 if (a.value.match(/^body$/)) {
22858 node.className = '';
22869 this.cleanUpChildren(node);
22875 * Clean up MS wordisms...
22877 cleanWord : function(node)
22882 this.cleanWord(this.doc.body);
22885 if (node.nodeName == "#text") {
22886 // clean up silly Windows -- stuff?
22889 if (node.nodeName == "#comment") {
22890 node.parentNode.removeChild(node);
22891 // clean up silly Windows -- stuff?
22895 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22896 node.parentNode.removeChild(node);
22900 // remove - but keep children..
22901 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22902 while (node.childNodes.length) {
22903 var cn = node.childNodes[0];
22904 node.removeChild(cn);
22905 node.parentNode.insertBefore(cn, node);
22907 node.parentNode.removeChild(node);
22908 this.iterateChildren(node, this.cleanWord);
22912 if (node.className.length) {
22914 var cn = node.className.split(/\W+/);
22916 Roo.each(cn, function(cls) {
22917 if (cls.match(/Mso[a-zA-Z]+/)) {
22922 node.className = cna.length ? cna.join(' ') : '';
22924 node.removeAttribute("class");
22928 if (node.hasAttribute("lang")) {
22929 node.removeAttribute("lang");
22932 if (node.hasAttribute("style")) {
22934 var styles = node.getAttribute("style").split(";");
22936 Roo.each(styles, function(s) {
22937 if (!s.match(/:/)) {
22940 var kv = s.split(":");
22941 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22944 // what ever is left... we allow.
22947 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22948 if (!nstyle.length) {
22949 node.removeAttribute('style');
22952 this.iterateChildren(node, this.cleanWord);
22958 * iterateChildren of a Node, calling fn each time, using this as the scole..
22959 * @param {DomNode} node node to iterate children of.
22960 * @param {Function} fn method of this class to call on each item.
22962 iterateChildren : function(node, fn)
22964 if (!node.childNodes.length) {
22967 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22968 fn.call(this, node.childNodes[i])
22974 * cleanTableWidths.
22976 * Quite often pasting from word etc.. results in tables with column and widths.
22977 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22980 cleanTableWidths : function(node)
22985 this.cleanTableWidths(this.doc.body);
22990 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22993 Roo.log(node.tagName);
22994 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22995 this.iterateChildren(node, this.cleanTableWidths);
22998 if (node.hasAttribute('width')) {
22999 node.removeAttribute('width');
23003 if (node.hasAttribute("style")) {
23006 var styles = node.getAttribute("style").split(";");
23008 Roo.each(styles, function(s) {
23009 if (!s.match(/:/)) {
23012 var kv = s.split(":");
23013 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23016 // what ever is left... we allow.
23019 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23020 if (!nstyle.length) {
23021 node.removeAttribute('style');
23025 this.iterateChildren(node, this.cleanTableWidths);
23033 domToHTML : function(currentElement, depth, nopadtext) {
23035 depth = depth || 0;
23036 nopadtext = nopadtext || false;
23038 if (!currentElement) {
23039 return this.domToHTML(this.doc.body);
23042 //Roo.log(currentElement);
23044 var allText = false;
23045 var nodeName = currentElement.nodeName;
23046 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23048 if (nodeName == '#text') {
23050 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23055 if (nodeName != 'BODY') {
23058 // Prints the node tagName, such as <A>, <IMG>, etc
23061 for(i = 0; i < currentElement.attributes.length;i++) {
23063 var aname = currentElement.attributes.item(i).name;
23064 if (!currentElement.attributes.item(i).value.length) {
23067 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23070 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23079 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23082 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23087 // Traverse the tree
23089 var currentElementChild = currentElement.childNodes.item(i);
23090 var allText = true;
23091 var innerHTML = '';
23093 while (currentElementChild) {
23094 // Formatting code (indent the tree so it looks nice on the screen)
23095 var nopad = nopadtext;
23096 if (lastnode == 'SPAN') {
23100 if (currentElementChild.nodeName == '#text') {
23101 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23102 toadd = nopadtext ? toadd : toadd.trim();
23103 if (!nopad && toadd.length > 80) {
23104 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23106 innerHTML += toadd;
23109 currentElementChild = currentElement.childNodes.item(i);
23115 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23117 // Recursively traverse the tree structure of the child node
23118 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23119 lastnode = currentElementChild.nodeName;
23121 currentElementChild=currentElement.childNodes.item(i);
23127 // The remaining code is mostly for formatting the tree
23128 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23133 ret+= "</"+tagName+">";
23139 applyBlacklists : function()
23141 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23142 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23146 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23147 if (b.indexOf(tag) > -1) {
23150 this.white.push(tag);
23154 Roo.each(w, function(tag) {
23155 if (b.indexOf(tag) > -1) {
23158 if (this.white.indexOf(tag) > -1) {
23161 this.white.push(tag);
23166 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23167 if (w.indexOf(tag) > -1) {
23170 this.black.push(tag);
23174 Roo.each(b, function(tag) {
23175 if (w.indexOf(tag) > -1) {
23178 if (this.black.indexOf(tag) > -1) {
23181 this.black.push(tag);
23186 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23187 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23191 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23192 if (b.indexOf(tag) > -1) {
23195 this.cwhite.push(tag);
23199 Roo.each(w, function(tag) {
23200 if (b.indexOf(tag) > -1) {
23203 if (this.cwhite.indexOf(tag) > -1) {
23206 this.cwhite.push(tag);
23211 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23212 if (w.indexOf(tag) > -1) {
23215 this.cblack.push(tag);
23219 Roo.each(b, function(tag) {
23220 if (w.indexOf(tag) > -1) {
23223 if (this.cblack.indexOf(tag) > -1) {
23226 this.cblack.push(tag);
23231 setStylesheets : function(stylesheets)
23233 if(typeof(stylesheets) == 'string'){
23234 Roo.get(this.iframe.contentDocument.head).createChild({
23236 rel : 'stylesheet',
23245 Roo.each(stylesheets, function(s) {
23250 Roo.get(_this.iframe.contentDocument.head).createChild({
23252 rel : 'stylesheet',
23261 removeStylesheets : function()
23265 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23270 setStyle : function(style)
23272 Roo.get(this.iframe.contentDocument.head).createChild({
23281 // hide stuff that is not compatible
23295 * @event specialkey
23299 * @cfg {String} fieldClass @hide
23302 * @cfg {String} focusClass @hide
23305 * @cfg {String} autoCreate @hide
23308 * @cfg {String} inputType @hide
23311 * @cfg {String} invalidClass @hide
23314 * @cfg {String} invalidText @hide
23317 * @cfg {String} msgFx @hide
23320 * @cfg {String} validateOnBlur @hide
23324 Roo.HtmlEditorCore.white = [
23325 'area', 'br', 'img', 'input', 'hr', 'wbr',
23327 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23328 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23329 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23330 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23331 'table', 'ul', 'xmp',
23333 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23336 'dir', 'menu', 'ol', 'ul', 'dl',
23342 Roo.HtmlEditorCore.black = [
23343 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23345 'base', 'basefont', 'bgsound', 'blink', 'body',
23346 'frame', 'frameset', 'head', 'html', 'ilayer',
23347 'iframe', 'layer', 'link', 'meta', 'object',
23348 'script', 'style' ,'title', 'xml' // clean later..
23350 Roo.HtmlEditorCore.clean = [
23351 'script', 'style', 'title', 'xml'
23353 Roo.HtmlEditorCore.remove = [
23358 Roo.HtmlEditorCore.ablack = [
23362 Roo.HtmlEditorCore.aclean = [
23363 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23367 Roo.HtmlEditorCore.pwhite= [
23368 'http', 'https', 'mailto'
23371 // white listed style attributes.
23372 Roo.HtmlEditorCore.cwhite= [
23373 // 'text-align', /// default is to allow most things..
23379 // black listed style attributes.
23380 Roo.HtmlEditorCore.cblack= [
23381 // 'font-size' -- this can be set by the project
23385 Roo.HtmlEditorCore.swapCodes =[
23404 * @class Roo.bootstrap.HtmlEditor
23405 * @extends Roo.bootstrap.TextArea
23406 * Bootstrap HtmlEditor class
23409 * Create a new HtmlEditor
23410 * @param {Object} config The config object
23413 Roo.bootstrap.HtmlEditor = function(config){
23414 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23415 if (!this.toolbars) {
23416 this.toolbars = [];
23419 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23422 * @event initialize
23423 * Fires when the editor is fully initialized (including the iframe)
23424 * @param {HtmlEditor} this
23429 * Fires when the editor is first receives the focus. Any insertion must wait
23430 * until after this event.
23431 * @param {HtmlEditor} this
23435 * @event beforesync
23436 * Fires before the textarea is updated with content from the editor iframe. Return false
23437 * to cancel the sync.
23438 * @param {HtmlEditor} this
23439 * @param {String} html
23443 * @event beforepush
23444 * Fires before the iframe editor is updated with content from the textarea. Return false
23445 * to cancel the push.
23446 * @param {HtmlEditor} this
23447 * @param {String} html
23452 * Fires when the textarea is updated with content from the editor iframe.
23453 * @param {HtmlEditor} this
23454 * @param {String} html
23459 * Fires when the iframe editor is updated with content from the textarea.
23460 * @param {HtmlEditor} this
23461 * @param {String} html
23465 * @event editmodechange
23466 * Fires when the editor switches edit modes
23467 * @param {HtmlEditor} this
23468 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23470 editmodechange: true,
23472 * @event editorevent
23473 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23474 * @param {HtmlEditor} this
23478 * @event firstfocus
23479 * Fires when on first focus - needed by toolbars..
23480 * @param {HtmlEditor} this
23485 * Auto save the htmlEditor value as a file into Events
23486 * @param {HtmlEditor} this
23490 * @event savedpreview
23491 * preview the saved version of htmlEditor
23492 * @param {HtmlEditor} this
23499 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23503 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23508 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23513 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23518 * @cfg {Number} height (in pixels)
23522 * @cfg {Number} width (in pixels)
23527 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23530 stylesheets: false,
23535 // private properties
23536 validationEvent : false,
23538 initialized : false,
23541 onFocus : Roo.emptyFn,
23543 hideMode:'offsets',
23545 tbContainer : false,
23549 toolbarContainer :function() {
23550 return this.wrap.select('.x-html-editor-tb',true).first();
23554 * Protected method that will not generally be called directly. It
23555 * is called when the editor creates its toolbar. Override this method if you need to
23556 * add custom toolbar buttons.
23557 * @param {HtmlEditor} editor
23559 createToolbar : function(){
23560 Roo.log('renewing');
23561 Roo.log("create toolbars");
23563 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23564 this.toolbars[0].render(this.toolbarContainer());
23568 // if (!editor.toolbars || !editor.toolbars.length) {
23569 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23572 // for (var i =0 ; i < editor.toolbars.length;i++) {
23573 // editor.toolbars[i] = Roo.factory(
23574 // typeof(editor.toolbars[i]) == 'string' ?
23575 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23576 // Roo.bootstrap.HtmlEditor);
23577 // editor.toolbars[i].init(editor);
23583 onRender : function(ct, position)
23585 // Roo.log("Call onRender: " + this.xtype);
23587 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23589 this.wrap = this.inputEl().wrap({
23590 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23593 this.editorcore.onRender(ct, position);
23595 if (this.resizable) {
23596 this.resizeEl = new Roo.Resizable(this.wrap, {
23600 minHeight : this.height,
23601 height: this.height,
23602 handles : this.resizable,
23605 resize : function(r, w, h) {
23606 _t.onResize(w,h); // -something
23612 this.createToolbar(this);
23615 if(!this.width && this.resizable){
23616 this.setSize(this.wrap.getSize());
23618 if (this.resizeEl) {
23619 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23620 // should trigger onReize..
23626 onResize : function(w, h)
23628 Roo.log('resize: ' +w + ',' + h );
23629 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23633 if(this.inputEl() ){
23634 if(typeof w == 'number'){
23635 var aw = w - this.wrap.getFrameWidth('lr');
23636 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23639 if(typeof h == 'number'){
23640 var tbh = -11; // fixme it needs to tool bar size!
23641 for (var i =0; i < this.toolbars.length;i++) {
23642 // fixme - ask toolbars for heights?
23643 tbh += this.toolbars[i].el.getHeight();
23644 //if (this.toolbars[i].footer) {
23645 // tbh += this.toolbars[i].footer.el.getHeight();
23653 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23654 ah -= 5; // knock a few pixes off for look..
23655 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23659 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23660 this.editorcore.onResize(ew,eh);
23665 * Toggles the editor between standard and source edit mode.
23666 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23668 toggleSourceEdit : function(sourceEditMode)
23670 this.editorcore.toggleSourceEdit(sourceEditMode);
23672 if(this.editorcore.sourceEditMode){
23673 Roo.log('editor - showing textarea');
23676 // Roo.log(this.syncValue());
23678 this.inputEl().removeClass(['hide', 'x-hidden']);
23679 this.inputEl().dom.removeAttribute('tabIndex');
23680 this.inputEl().focus();
23682 Roo.log('editor - hiding textarea');
23684 // Roo.log(this.pushValue());
23687 this.inputEl().addClass(['hide', 'x-hidden']);
23688 this.inputEl().dom.setAttribute('tabIndex', -1);
23689 //this.deferFocus();
23692 if(this.resizable){
23693 this.setSize(this.wrap.getSize());
23696 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23699 // private (for BoxComponent)
23700 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23702 // private (for BoxComponent)
23703 getResizeEl : function(){
23707 // private (for BoxComponent)
23708 getPositionEl : function(){
23713 initEvents : function(){
23714 this.originalValue = this.getValue();
23718 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23721 // markInvalid : Roo.emptyFn,
23723 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23726 // clearInvalid : Roo.emptyFn,
23728 setValue : function(v){
23729 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23730 this.editorcore.pushValue();
23735 deferFocus : function(){
23736 this.focus.defer(10, this);
23740 focus : function(){
23741 this.editorcore.focus();
23747 onDestroy : function(){
23753 for (var i =0; i < this.toolbars.length;i++) {
23754 // fixme - ask toolbars for heights?
23755 this.toolbars[i].onDestroy();
23758 this.wrap.dom.innerHTML = '';
23759 this.wrap.remove();
23764 onFirstFocus : function(){
23765 //Roo.log("onFirstFocus");
23766 this.editorcore.onFirstFocus();
23767 for (var i =0; i < this.toolbars.length;i++) {
23768 this.toolbars[i].onFirstFocus();
23774 syncValue : function()
23776 this.editorcore.syncValue();
23779 pushValue : function()
23781 this.editorcore.pushValue();
23785 // hide stuff that is not compatible
23799 * @event specialkey
23803 * @cfg {String} fieldClass @hide
23806 * @cfg {String} focusClass @hide
23809 * @cfg {String} autoCreate @hide
23812 * @cfg {String} inputType @hide
23815 * @cfg {String} invalidClass @hide
23818 * @cfg {String} invalidText @hide
23821 * @cfg {String} msgFx @hide
23824 * @cfg {String} validateOnBlur @hide
23833 Roo.namespace('Roo.bootstrap.htmleditor');
23835 * @class Roo.bootstrap.HtmlEditorToolbar1
23840 new Roo.bootstrap.HtmlEditor({
23843 new Roo.bootstrap.HtmlEditorToolbar1({
23844 disable : { fonts: 1 , format: 1, ..., ... , ...],
23850 * @cfg {Object} disable List of elements to disable..
23851 * @cfg {Array} btns List of additional buttons.
23855 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23858 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23861 Roo.apply(this, config);
23863 // default disabled, based on 'good practice'..
23864 this.disable = this.disable || {};
23865 Roo.applyIf(this.disable, {
23868 specialElements : true
23870 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23872 this.editor = config.editor;
23873 this.editorcore = config.editor.editorcore;
23875 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23877 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23878 // dont call parent... till later.
23880 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23885 editorcore : false,
23890 "h1","h2","h3","h4","h5","h6",
23892 "abbr", "acronym", "address", "cite", "samp", "var",
23896 onRender : function(ct, position)
23898 // Roo.log("Call onRender: " + this.xtype);
23900 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23902 this.el.dom.style.marginBottom = '0';
23904 var editorcore = this.editorcore;
23905 var editor= this.editor;
23908 var btn = function(id,cmd , toggle, handler, html){
23910 var event = toggle ? 'toggle' : 'click';
23915 xns: Roo.bootstrap,
23918 enableToggle:toggle !== false,
23920 pressed : toggle ? false : null,
23923 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23924 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23930 // var cb_box = function...
23935 xns: Roo.bootstrap,
23936 glyphicon : 'font',
23940 xns: Roo.bootstrap,
23944 Roo.each(this.formats, function(f) {
23945 style.menu.items.push({
23947 xns: Roo.bootstrap,
23948 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23953 editorcore.insertTag(this.tagname);
23960 children.push(style);
23962 btn('bold',false,true);
23963 btn('italic',false,true);
23964 btn('align-left', 'justifyleft',true);
23965 btn('align-center', 'justifycenter',true);
23966 btn('align-right' , 'justifyright',true);
23967 btn('link', false, false, function(btn) {
23968 //Roo.log("create link?");
23969 var url = prompt(this.createLinkText, this.defaultLinkValue);
23970 if(url && url != 'http:/'+'/'){
23971 this.editorcore.relayCmd('createlink', url);
23974 btn('list','insertunorderedlist',true);
23975 btn('pencil', false,true, function(btn){
23977 this.toggleSourceEdit(btn.pressed);
23980 if (this.editor.btns.length > 0) {
23981 for (var i = 0; i<this.editor.btns.length; i++) {
23982 children.push(this.editor.btns[i]);
23990 xns: Roo.bootstrap,
23995 xns: Roo.bootstrap,
24000 cog.menu.items.push({
24002 xns: Roo.bootstrap,
24003 html : Clean styles,
24008 editorcore.insertTag(this.tagname);
24017 this.xtype = 'NavSimplebar';
24019 for(var i=0;i< children.length;i++) {
24021 this.buttons.add(this.addxtypeChild(children[i]));
24025 editor.on('editorevent', this.updateToolbar, this);
24027 onBtnClick : function(id)
24029 this.editorcore.relayCmd(id);
24030 this.editorcore.focus();
24034 * Protected method that will not generally be called directly. It triggers
24035 * a toolbar update by reading the markup state of the current selection in the editor.
24037 updateToolbar: function(){
24039 if(!this.editorcore.activated){
24040 this.editor.onFirstFocus(); // is this neeed?
24044 var btns = this.buttons;
24045 var doc = this.editorcore.doc;
24046 btns.get('bold').setActive(doc.queryCommandState('bold'));
24047 btns.get('italic').setActive(doc.queryCommandState('italic'));
24048 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24050 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24051 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24052 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24054 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24055 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24058 var ans = this.editorcore.getAllAncestors();
24059 if (this.formatCombo) {
24062 var store = this.formatCombo.store;
24063 this.formatCombo.setValue("");
24064 for (var i =0; i < ans.length;i++) {
24065 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24067 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24075 // hides menus... - so this cant be on a menu...
24076 Roo.bootstrap.MenuMgr.hideAll();
24078 Roo.bootstrap.MenuMgr.hideAll();
24079 //this.editorsyncValue();
24081 onFirstFocus: function() {
24082 this.buttons.each(function(item){
24086 toggleSourceEdit : function(sourceEditMode){
24089 if(sourceEditMode){
24090 Roo.log("disabling buttons");
24091 this.buttons.each( function(item){
24092 if(item.cmd != 'pencil'){
24098 Roo.log("enabling buttons");
24099 if(this.editorcore.initialized){
24100 this.buttons.each( function(item){
24106 Roo.log("calling toggole on editor");
24107 // tell the editor that it's been pressed..
24108 this.editor.toggleSourceEdit(sourceEditMode);
24118 * @class Roo.bootstrap.Table.AbstractSelectionModel
24119 * @extends Roo.util.Observable
24120 * Abstract base class for grid SelectionModels. It provides the interface that should be
24121 * implemented by descendant classes. This class should not be directly instantiated.
24124 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24125 this.locked = false;
24126 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24130 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24131 /** @ignore Called by the grid automatically. Do not call directly. */
24132 init : function(grid){
24138 * Locks the selections.
24141 this.locked = true;
24145 * Unlocks the selections.
24147 unlock : function(){
24148 this.locked = false;
24152 * Returns true if the selections are locked.
24153 * @return {Boolean}
24155 isLocked : function(){
24156 return this.locked;
24160 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24161 * @class Roo.bootstrap.Table.RowSelectionModel
24162 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24163 * It supports multiple selections and keyboard selection/navigation.
24165 * @param {Object} config
24168 Roo.bootstrap.Table.RowSelectionModel = function(config){
24169 Roo.apply(this, config);
24170 this.selections = new Roo.util.MixedCollection(false, function(o){
24175 this.lastActive = false;
24179 * @event selectionchange
24180 * Fires when the selection changes
24181 * @param {SelectionModel} this
24183 "selectionchange" : true,
24185 * @event afterselectionchange
24186 * Fires after the selection changes (eg. by key press or clicking)
24187 * @param {SelectionModel} this
24189 "afterselectionchange" : true,
24191 * @event beforerowselect
24192 * Fires when a row is selected being selected, return false to cancel.
24193 * @param {SelectionModel} this
24194 * @param {Number} rowIndex The selected index
24195 * @param {Boolean} keepExisting False if other selections will be cleared
24197 "beforerowselect" : true,
24200 * Fires when a row is selected.
24201 * @param {SelectionModel} this
24202 * @param {Number} rowIndex The selected index
24203 * @param {Roo.data.Record} r The record
24205 "rowselect" : true,
24207 * @event rowdeselect
24208 * Fires when a row is deselected.
24209 * @param {SelectionModel} this
24210 * @param {Number} rowIndex The selected index
24212 "rowdeselect" : true
24214 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24215 this.locked = false;
24218 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24220 * @cfg {Boolean} singleSelect
24221 * True to allow selection of only one row at a time (defaults to false)
24223 singleSelect : false,
24226 initEvents : function()
24229 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24230 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24231 //}else{ // allow click to work like normal
24232 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24234 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24235 this.grid.on("rowclick", this.handleMouseDown, this);
24237 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24238 "up" : function(e){
24240 this.selectPrevious(e.shiftKey);
24241 }else if(this.last !== false && this.lastActive !== false){
24242 var last = this.last;
24243 this.selectRange(this.last, this.lastActive-1);
24244 this.grid.getView().focusRow(this.lastActive);
24245 if(last !== false){
24249 this.selectFirstRow();
24251 this.fireEvent("afterselectionchange", this);
24253 "down" : function(e){
24255 this.selectNext(e.shiftKey);
24256 }else if(this.last !== false && this.lastActive !== false){
24257 var last = this.last;
24258 this.selectRange(this.last, this.lastActive+1);
24259 this.grid.getView().focusRow(this.lastActive);
24260 if(last !== false){
24264 this.selectFirstRow();
24266 this.fireEvent("afterselectionchange", this);
24270 this.grid.store.on('load', function(){
24271 this.selections.clear();
24274 var view = this.grid.view;
24275 view.on("refresh", this.onRefresh, this);
24276 view.on("rowupdated", this.onRowUpdated, this);
24277 view.on("rowremoved", this.onRemove, this);
24282 onRefresh : function()
24284 var ds = this.grid.store, i, v = this.grid.view;
24285 var s = this.selections;
24286 s.each(function(r){
24287 if((i = ds.indexOfId(r.id)) != -1){
24296 onRemove : function(v, index, r){
24297 this.selections.remove(r);
24301 onRowUpdated : function(v, index, r){
24302 if(this.isSelected(r)){
24303 v.onRowSelect(index);
24309 * @param {Array} records The records to select
24310 * @param {Boolean} keepExisting (optional) True to keep existing selections
24312 selectRecords : function(records, keepExisting)
24315 this.clearSelections();
24317 var ds = this.grid.store;
24318 for(var i = 0, len = records.length; i < len; i++){
24319 this.selectRow(ds.indexOf(records[i]), true);
24324 * Gets the number of selected rows.
24327 getCount : function(){
24328 return this.selections.length;
24332 * Selects the first row in the grid.
24334 selectFirstRow : function(){
24339 * Select the last row.
24340 * @param {Boolean} keepExisting (optional) True to keep existing selections
24342 selectLastRow : function(keepExisting){
24343 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24344 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24348 * Selects the row immediately following the last selected row.
24349 * @param {Boolean} keepExisting (optional) True to keep existing selections
24351 selectNext : function(keepExisting)
24353 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24354 this.selectRow(this.last+1, keepExisting);
24355 this.grid.getView().focusRow(this.last);
24360 * Selects the row that precedes the last selected row.
24361 * @param {Boolean} keepExisting (optional) True to keep existing selections
24363 selectPrevious : function(keepExisting){
24365 this.selectRow(this.last-1, keepExisting);
24366 this.grid.getView().focusRow(this.last);
24371 * Returns the selected records
24372 * @return {Array} Array of selected records
24374 getSelections : function(){
24375 return [].concat(this.selections.items);
24379 * Returns the first selected record.
24382 getSelected : function(){
24383 return this.selections.itemAt(0);
24388 * Clears all selections.
24390 clearSelections : function(fast)
24396 var ds = this.grid.store;
24397 var s = this.selections;
24398 s.each(function(r){
24399 this.deselectRow(ds.indexOfId(r.id));
24403 this.selections.clear();
24410 * Selects all rows.
24412 selectAll : function(){
24416 this.selections.clear();
24417 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24418 this.selectRow(i, true);
24423 * Returns True if there is a selection.
24424 * @return {Boolean}
24426 hasSelection : function(){
24427 return this.selections.length > 0;
24431 * Returns True if the specified row is selected.
24432 * @param {Number/Record} record The record or index of the record to check
24433 * @return {Boolean}
24435 isSelected : function(index){
24436 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24437 return (r && this.selections.key(r.id) ? true : false);
24441 * Returns True if the specified record id is selected.
24442 * @param {String} id The id of record to check
24443 * @return {Boolean}
24445 isIdSelected : function(id){
24446 return (this.selections.key(id) ? true : false);
24451 handleMouseDBClick : function(e, t){
24455 handleMouseDown : function(e, t)
24457 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24458 if(this.isLocked() || rowIndex < 0 ){
24461 if(e.shiftKey && this.last !== false){
24462 var last = this.last;
24463 this.selectRange(last, rowIndex, e.ctrlKey);
24464 this.last = last; // reset the last
24468 var isSelected = this.isSelected(rowIndex);
24469 //Roo.log("select row:" + rowIndex);
24471 this.deselectRow(rowIndex);
24473 this.selectRow(rowIndex, true);
24477 if(e.button !== 0 && isSelected){
24478 alert('rowIndex 2: ' + rowIndex);
24479 view.focusRow(rowIndex);
24480 }else if(e.ctrlKey && isSelected){
24481 this.deselectRow(rowIndex);
24482 }else if(!isSelected){
24483 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24484 view.focusRow(rowIndex);
24488 this.fireEvent("afterselectionchange", this);
24491 handleDragableRowClick : function(grid, rowIndex, e)
24493 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24494 this.selectRow(rowIndex, false);
24495 grid.view.focusRow(rowIndex);
24496 this.fireEvent("afterselectionchange", this);
24501 * Selects multiple rows.
24502 * @param {Array} rows Array of the indexes of the row to select
24503 * @param {Boolean} keepExisting (optional) True to keep existing selections
24505 selectRows : function(rows, keepExisting){
24507 this.clearSelections();
24509 for(var i = 0, len = rows.length; i < len; i++){
24510 this.selectRow(rows[i], true);
24515 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24516 * @param {Number} startRow The index of the first row in the range
24517 * @param {Number} endRow The index of the last row in the range
24518 * @param {Boolean} keepExisting (optional) True to retain existing selections
24520 selectRange : function(startRow, endRow, keepExisting){
24525 this.clearSelections();
24527 if(startRow <= endRow){
24528 for(var i = startRow; i <= endRow; i++){
24529 this.selectRow(i, true);
24532 for(var i = startRow; i >= endRow; i--){
24533 this.selectRow(i, true);
24539 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24540 * @param {Number} startRow The index of the first row in the range
24541 * @param {Number} endRow The index of the last row in the range
24543 deselectRange : function(startRow, endRow, preventViewNotify){
24547 for(var i = startRow; i <= endRow; i++){
24548 this.deselectRow(i, preventViewNotify);
24554 * @param {Number} row The index of the row to select
24555 * @param {Boolean} keepExisting (optional) True to keep existing selections
24557 selectRow : function(index, keepExisting, preventViewNotify)
24559 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24562 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24563 if(!keepExisting || this.singleSelect){
24564 this.clearSelections();
24567 var r = this.grid.store.getAt(index);
24568 //console.log('selectRow - record id :' + r.id);
24570 this.selections.add(r);
24571 this.last = this.lastActive = index;
24572 if(!preventViewNotify){
24573 var proxy = new Roo.Element(
24574 this.grid.getRowDom(index)
24576 proxy.addClass('bg-info info');
24578 this.fireEvent("rowselect", this, index, r);
24579 this.fireEvent("selectionchange", this);
24585 * @param {Number} row The index of the row to deselect
24587 deselectRow : function(index, preventViewNotify)
24592 if(this.last == index){
24595 if(this.lastActive == index){
24596 this.lastActive = false;
24599 var r = this.grid.store.getAt(index);
24604 this.selections.remove(r);
24605 //.console.log('deselectRow - record id :' + r.id);
24606 if(!preventViewNotify){
24608 var proxy = new Roo.Element(
24609 this.grid.getRowDom(index)
24611 proxy.removeClass('bg-info info');
24613 this.fireEvent("rowdeselect", this, index);
24614 this.fireEvent("selectionchange", this);
24618 restoreLast : function(){
24620 this.last = this._last;
24625 acceptsNav : function(row, col, cm){
24626 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24630 onEditorKey : function(field, e){
24631 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24636 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24638 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24640 }else if(k == e.ENTER && !e.ctrlKey){
24644 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24646 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24648 }else if(k == e.ESC){
24652 g.startEditing(newCell[0], newCell[1]);
24658 * Ext JS Library 1.1.1
24659 * Copyright(c) 2006-2007, Ext JS, LLC.
24661 * Originally Released Under LGPL - original licence link has changed is not relivant.
24664 * <script type="text/javascript">
24668 * @class Roo.bootstrap.PagingToolbar
24669 * @extends Roo.bootstrap.NavSimplebar
24670 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24672 * Create a new PagingToolbar
24673 * @param {Object} config The config object
24674 * @param {Roo.data.Store} store
24676 Roo.bootstrap.PagingToolbar = function(config)
24678 // old args format still supported... - xtype is prefered..
24679 // created from xtype...
24681 this.ds = config.dataSource;
24683 if (config.store && !this.ds) {
24684 this.store= Roo.factory(config.store, Roo.data);
24685 this.ds = this.store;
24686 this.ds.xmodule = this.xmodule || false;
24689 this.toolbarItems = [];
24690 if (config.items) {
24691 this.toolbarItems = config.items;
24694 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24699 this.bind(this.ds);
24702 if (Roo.bootstrap.version == 4) {
24703 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24705 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24710 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24712 * @cfg {Roo.data.Store} dataSource
24713 * The underlying data store providing the paged data
24716 * @cfg {String/HTMLElement/Element} container
24717 * container The id or element that will contain the toolbar
24720 * @cfg {Boolean} displayInfo
24721 * True to display the displayMsg (defaults to false)
24724 * @cfg {Number} pageSize
24725 * The number of records to display per page (defaults to 20)
24729 * @cfg {String} displayMsg
24730 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24732 displayMsg : 'Displaying {0} - {1} of {2}',
24734 * @cfg {String} emptyMsg
24735 * The message to display when no records are found (defaults to "No data to display")
24737 emptyMsg : 'No data to display',
24739 * Customizable piece of the default paging text (defaults to "Page")
24742 beforePageText : "Page",
24744 * Customizable piece of the default paging text (defaults to "of %0")
24747 afterPageText : "of {0}",
24749 * Customizable piece of the default paging text (defaults to "First Page")
24752 firstText : "First Page",
24754 * Customizable piece of the default paging text (defaults to "Previous Page")
24757 prevText : "Previous Page",
24759 * Customizable piece of the default paging text (defaults to "Next Page")
24762 nextText : "Next Page",
24764 * Customizable piece of the default paging text (defaults to "Last Page")
24767 lastText : "Last Page",
24769 * Customizable piece of the default paging text (defaults to "Refresh")
24772 refreshText : "Refresh",
24776 onRender : function(ct, position)
24778 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24779 this.navgroup.parentId = this.id;
24780 this.navgroup.onRender(this.el, null);
24781 // add the buttons to the navgroup
24783 if(this.displayInfo){
24784 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24785 this.displayEl = this.el.select('.x-paging-info', true).first();
24786 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24787 // this.displayEl = navel.el.select('span',true).first();
24793 Roo.each(_this.buttons, function(e){ // this might need to use render????
24794 Roo.factory(e).render(_this.el);
24798 Roo.each(_this.toolbarItems, function(e) {
24799 _this.navgroup.addItem(e);
24803 this.first = this.navgroup.addItem({
24804 tooltip: this.firstText,
24805 cls: "prev btn-outline-secondary",
24806 html : ' <i class="fa fa-step-backward"></i>',
24808 preventDefault: true,
24809 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24812 this.prev = this.navgroup.addItem({
24813 tooltip: this.prevText,
24814 cls: "prev btn-outline-secondary",
24815 html : ' <i class="fa fa-backward"></i>',
24817 preventDefault: true,
24818 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24820 //this.addSeparator();
24823 var field = this.navgroup.addItem( {
24825 cls : 'x-paging-position btn-outline-secondary',
24827 html : this.beforePageText +
24828 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24829 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24832 this.field = field.el.select('input', true).first();
24833 this.field.on("keydown", this.onPagingKeydown, this);
24834 this.field.on("focus", function(){this.dom.select();});
24837 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24838 //this.field.setHeight(18);
24839 //this.addSeparator();
24840 this.next = this.navgroup.addItem({
24841 tooltip: this.nextText,
24842 cls: "next btn-outline-secondary",
24843 html : ' <i class="fa fa-forward"></i>',
24845 preventDefault: true,
24846 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24848 this.last = this.navgroup.addItem({
24849 tooltip: this.lastText,
24850 html : ' <i class="fa fa-step-forward"></i>',
24851 cls: "next btn-outline-secondary",
24853 preventDefault: true,
24854 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24856 //this.addSeparator();
24857 this.loading = this.navgroup.addItem({
24858 tooltip: this.refreshText,
24859 cls: "btn-outline-secondary",
24860 html : ' <i class="fa fa-refresh"></i>',
24861 preventDefault: true,
24862 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24868 updateInfo : function(){
24869 if(this.displayEl){
24870 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24871 var msg = count == 0 ?
24875 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24877 this.displayEl.update(msg);
24882 onLoad : function(ds, r, o)
24884 this.cursor = o.params.start ? o.params.start : 0;
24886 var d = this.getPageData(),
24891 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24892 this.field.dom.value = ap;
24893 this.first.setDisabled(ap == 1);
24894 this.prev.setDisabled(ap == 1);
24895 this.next.setDisabled(ap == ps);
24896 this.last.setDisabled(ap == ps);
24897 this.loading.enable();
24902 getPageData : function(){
24903 var total = this.ds.getTotalCount();
24906 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24907 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24912 onLoadError : function(){
24913 this.loading.enable();
24917 onPagingKeydown : function(e){
24918 var k = e.getKey();
24919 var d = this.getPageData();
24921 var v = this.field.dom.value, pageNum;
24922 if(!v || isNaN(pageNum = parseInt(v, 10))){
24923 this.field.dom.value = d.activePage;
24926 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24927 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24930 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))
24932 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24933 this.field.dom.value = pageNum;
24934 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24937 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24939 var v = this.field.dom.value, pageNum;
24940 var increment = (e.shiftKey) ? 10 : 1;
24941 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24944 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24945 this.field.dom.value = d.activePage;
24948 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24950 this.field.dom.value = parseInt(v, 10) + increment;
24951 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24952 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24959 beforeLoad : function(){
24961 this.loading.disable();
24966 onClick : function(which){
24975 ds.load({params:{start: 0, limit: this.pageSize}});
24978 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24981 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24984 var total = ds.getTotalCount();
24985 var extra = total % this.pageSize;
24986 var lastStart = extra ? (total - extra) : total-this.pageSize;
24987 ds.load({params:{start: lastStart, limit: this.pageSize}});
24990 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24996 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24997 * @param {Roo.data.Store} store The data store to unbind
24999 unbind : function(ds){
25000 ds.un("beforeload", this.beforeLoad, this);
25001 ds.un("load", this.onLoad, this);
25002 ds.un("loadexception", this.onLoadError, this);
25003 ds.un("remove", this.updateInfo, this);
25004 ds.un("add", this.updateInfo, this);
25005 this.ds = undefined;
25009 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25010 * @param {Roo.data.Store} store The data store to bind
25012 bind : function(ds){
25013 ds.on("beforeload", this.beforeLoad, this);
25014 ds.on("load", this.onLoad, this);
25015 ds.on("loadexception", this.onLoadError, this);
25016 ds.on("remove", this.updateInfo, this);
25017 ds.on("add", this.updateInfo, this);
25028 * @class Roo.bootstrap.MessageBar
25029 * @extends Roo.bootstrap.Component
25030 * Bootstrap MessageBar class
25031 * @cfg {String} html contents of the MessageBar
25032 * @cfg {String} weight (info | success | warning | danger) default info
25033 * @cfg {String} beforeClass insert the bar before the given class
25034 * @cfg {Boolean} closable (true | false) default false
25035 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25038 * Create a new Element
25039 * @param {Object} config The config object
25042 Roo.bootstrap.MessageBar = function(config){
25043 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25046 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25052 beforeClass: 'bootstrap-sticky-wrap',
25054 getAutoCreate : function(){
25058 cls: 'alert alert-dismissable alert-' + this.weight,
25063 html: this.html || ''
25069 cfg.cls += ' alert-messages-fixed';
25083 onRender : function(ct, position)
25085 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25088 var cfg = Roo.apply({}, this.getAutoCreate());
25092 cfg.cls += ' ' + this.cls;
25095 cfg.style = this.style;
25097 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25099 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25102 this.el.select('>button.close').on('click', this.hide, this);
25108 if (!this.rendered) {
25114 this.fireEvent('show', this);
25120 if (!this.rendered) {
25126 this.fireEvent('hide', this);
25129 update : function()
25131 // var e = this.el.dom.firstChild;
25133 // if(this.closable){
25134 // e = e.nextSibling;
25137 // e.data = this.html || '';
25139 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25155 * @class Roo.bootstrap.Graph
25156 * @extends Roo.bootstrap.Component
25157 * Bootstrap Graph class
25161 @cfg {String} graphtype bar | vbar | pie
25162 @cfg {number} g_x coodinator | centre x (pie)
25163 @cfg {number} g_y coodinator | centre y (pie)
25164 @cfg {number} g_r radius (pie)
25165 @cfg {number} g_height height of the chart (respected by all elements in the set)
25166 @cfg {number} g_width width of the chart (respected by all elements in the set)
25167 @cfg {Object} title The title of the chart
25170 -opts (object) options for the chart
25172 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25173 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25175 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.
25176 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25178 o stretch (boolean)
25180 -opts (object) options for the pie
25183 o startAngle (number)
25184 o endAngle (number)
25188 * Create a new Input
25189 * @param {Object} config The config object
25192 Roo.bootstrap.Graph = function(config){
25193 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25199 * The img click event for the img.
25200 * @param {Roo.EventObject} e
25206 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25217 //g_colors: this.colors,
25224 getAutoCreate : function(){
25235 onRender : function(ct,position){
25238 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25240 if (typeof(Raphael) == 'undefined') {
25241 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25245 this.raphael = Raphael(this.el.dom);
25247 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25248 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25249 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25250 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25252 r.text(160, 10, "Single Series Chart").attr(txtattr);
25253 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25254 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25255 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25257 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25258 r.barchart(330, 10, 300, 220, data1);
25259 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25260 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25263 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25264 // r.barchart(30, 30, 560, 250, xdata, {
25265 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25266 // axis : "0 0 1 1",
25267 // axisxlabels : xdata
25268 // //yvalues : cols,
25271 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25273 // this.load(null,xdata,{
25274 // axis : "0 0 1 1",
25275 // axisxlabels : xdata
25280 load : function(graphtype,xdata,opts)
25282 this.raphael.clear();
25284 graphtype = this.graphtype;
25289 var r = this.raphael,
25290 fin = function () {
25291 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25293 fout = function () {
25294 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25296 pfin = function() {
25297 this.sector.stop();
25298 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25301 this.label[0].stop();
25302 this.label[0].attr({ r: 7.5 });
25303 this.label[1].attr({ "font-weight": 800 });
25306 pfout = function() {
25307 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25310 this.label[0].animate({ r: 5 }, 500, "bounce");
25311 this.label[1].attr({ "font-weight": 400 });
25317 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25320 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25323 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25324 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25326 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25333 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25338 setTitle: function(o)
25343 initEvents: function() {
25346 this.el.on('click', this.onClick, this);
25350 onClick : function(e)
25352 Roo.log('img onclick');
25353 this.fireEvent('click', this, e);
25365 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25368 * @class Roo.bootstrap.dash.NumberBox
25369 * @extends Roo.bootstrap.Component
25370 * Bootstrap NumberBox class
25371 * @cfg {String} headline Box headline
25372 * @cfg {String} content Box content
25373 * @cfg {String} icon Box icon
25374 * @cfg {String} footer Footer text
25375 * @cfg {String} fhref Footer href
25378 * Create a new NumberBox
25379 * @param {Object} config The config object
25383 Roo.bootstrap.dash.NumberBox = function(config){
25384 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25388 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25397 getAutoCreate : function(){
25401 cls : 'small-box ',
25409 cls : 'roo-headline',
25410 html : this.headline
25414 cls : 'roo-content',
25415 html : this.content
25429 cls : 'ion ' + this.icon
25438 cls : 'small-box-footer',
25439 href : this.fhref || '#',
25443 cfg.cn.push(footer);
25450 onRender : function(ct,position){
25451 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25458 setHeadline: function (value)
25460 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25463 setFooter: function (value, href)
25465 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25468 this.el.select('a.small-box-footer',true).first().attr('href', href);
25473 setContent: function (value)
25475 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25478 initEvents: function()
25492 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25495 * @class Roo.bootstrap.dash.TabBox
25496 * @extends Roo.bootstrap.Component
25497 * Bootstrap TabBox class
25498 * @cfg {String} title Title of the TabBox
25499 * @cfg {String} icon Icon of the TabBox
25500 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25501 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25504 * Create a new TabBox
25505 * @param {Object} config The config object
25509 Roo.bootstrap.dash.TabBox = function(config){
25510 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25515 * When a pane is added
25516 * @param {Roo.bootstrap.dash.TabPane} pane
25520 * @event activatepane
25521 * When a pane is activated
25522 * @param {Roo.bootstrap.dash.TabPane} pane
25524 "activatepane" : true
25532 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25537 tabScrollable : false,
25539 getChildContainer : function()
25541 return this.el.select('.tab-content', true).first();
25544 getAutoCreate : function(){
25548 cls: 'pull-left header',
25556 cls: 'fa ' + this.icon
25562 cls: 'nav nav-tabs pull-right',
25568 if(this.tabScrollable){
25575 cls: 'nav nav-tabs pull-right',
25586 cls: 'nav-tabs-custom',
25591 cls: 'tab-content no-padding',
25599 initEvents : function()
25601 //Roo.log('add add pane handler');
25602 this.on('addpane', this.onAddPane, this);
25605 * Updates the box title
25606 * @param {String} html to set the title to.
25608 setTitle : function(value)
25610 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25612 onAddPane : function(pane)
25614 this.panes.push(pane);
25615 //Roo.log('addpane');
25617 // tabs are rendere left to right..
25618 if(!this.showtabs){
25622 var ctr = this.el.select('.nav-tabs', true).first();
25625 var existing = ctr.select('.nav-tab',true);
25626 var qty = existing.getCount();;
25629 var tab = ctr.createChild({
25631 cls : 'nav-tab' + (qty ? '' : ' active'),
25639 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25642 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25644 pane.el.addClass('active');
25649 onTabClick : function(ev,un,ob,pane)
25651 //Roo.log('tab - prev default');
25652 ev.preventDefault();
25655 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25656 pane.tab.addClass('active');
25657 //Roo.log(pane.title);
25658 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25659 // technically we should have a deactivate event.. but maybe add later.
25660 // and it should not de-activate the selected tab...
25661 this.fireEvent('activatepane', pane);
25662 pane.el.addClass('active');
25663 pane.fireEvent('activate');
25668 getActivePane : function()
25671 Roo.each(this.panes, function(p) {
25672 if(p.el.hasClass('active')){
25693 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25695 * @class Roo.bootstrap.TabPane
25696 * @extends Roo.bootstrap.Component
25697 * Bootstrap TabPane class
25698 * @cfg {Boolean} active (false | true) Default false
25699 * @cfg {String} title title of panel
25703 * Create a new TabPane
25704 * @param {Object} config The config object
25707 Roo.bootstrap.dash.TabPane = function(config){
25708 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25714 * When a pane is activated
25715 * @param {Roo.bootstrap.dash.TabPane} pane
25722 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25727 // the tabBox that this is attached to.
25730 getAutoCreate : function()
25738 cfg.cls += ' active';
25743 initEvents : function()
25745 //Roo.log('trigger add pane handler');
25746 this.parent().fireEvent('addpane', this)
25750 * Updates the tab title
25751 * @param {String} html to set the title to.
25753 setTitle: function(str)
25759 this.tab.select('a', true).first().dom.innerHTML = str;
25776 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25779 * @class Roo.bootstrap.menu.Menu
25780 * @extends Roo.bootstrap.Component
25781 * Bootstrap Menu class - container for Menu
25782 * @cfg {String} html Text of the menu
25783 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25784 * @cfg {String} icon Font awesome icon
25785 * @cfg {String} pos Menu align to (top | bottom) default bottom
25789 * Create a new Menu
25790 * @param {Object} config The config object
25794 Roo.bootstrap.menu.Menu = function(config){
25795 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25799 * @event beforeshow
25800 * Fires before this menu is displayed
25801 * @param {Roo.bootstrap.menu.Menu} this
25805 * @event beforehide
25806 * Fires before this menu is hidden
25807 * @param {Roo.bootstrap.menu.Menu} this
25812 * Fires after this menu is displayed
25813 * @param {Roo.bootstrap.menu.Menu} this
25818 * Fires after this menu is hidden
25819 * @param {Roo.bootstrap.menu.Menu} this
25824 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25825 * @param {Roo.bootstrap.menu.Menu} this
25826 * @param {Roo.EventObject} e
25833 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25837 weight : 'default',
25842 getChildContainer : function() {
25843 if(this.isSubMenu){
25847 return this.el.select('ul.dropdown-menu', true).first();
25850 getAutoCreate : function()
25855 cls : 'roo-menu-text',
25863 cls : 'fa ' + this.icon
25874 cls : 'dropdown-button btn btn-' + this.weight,
25879 cls : 'dropdown-toggle btn btn-' + this.weight,
25889 cls : 'dropdown-menu'
25895 if(this.pos == 'top'){
25896 cfg.cls += ' dropup';
25899 if(this.isSubMenu){
25902 cls : 'dropdown-menu'
25909 onRender : function(ct, position)
25911 this.isSubMenu = ct.hasClass('dropdown-submenu');
25913 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25916 initEvents : function()
25918 if(this.isSubMenu){
25922 this.hidden = true;
25924 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25925 this.triggerEl.on('click', this.onTriggerPress, this);
25927 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25928 this.buttonEl.on('click', this.onClick, this);
25934 if(this.isSubMenu){
25938 return this.el.select('ul.dropdown-menu', true).first();
25941 onClick : function(e)
25943 this.fireEvent("click", this, e);
25946 onTriggerPress : function(e)
25948 if (this.isVisible()) {
25955 isVisible : function(){
25956 return !this.hidden;
25961 this.fireEvent("beforeshow", this);
25963 this.hidden = false;
25964 this.el.addClass('open');
25966 Roo.get(document).on("mouseup", this.onMouseUp, this);
25968 this.fireEvent("show", this);
25975 this.fireEvent("beforehide", this);
25977 this.hidden = true;
25978 this.el.removeClass('open');
25980 Roo.get(document).un("mouseup", this.onMouseUp);
25982 this.fireEvent("hide", this);
25985 onMouseUp : function()
25999 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26002 * @class Roo.bootstrap.menu.Item
26003 * @extends Roo.bootstrap.Component
26004 * Bootstrap MenuItem class
26005 * @cfg {Boolean} submenu (true | false) default false
26006 * @cfg {String} html text of the item
26007 * @cfg {String} href the link
26008 * @cfg {Boolean} disable (true | false) default false
26009 * @cfg {Boolean} preventDefault (true | false) default true
26010 * @cfg {String} icon Font awesome icon
26011 * @cfg {String} pos Submenu align to (left | right) default right
26015 * Create a new Item
26016 * @param {Object} config The config object
26020 Roo.bootstrap.menu.Item = function(config){
26021 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26025 * Fires when the mouse is hovering over this menu
26026 * @param {Roo.bootstrap.menu.Item} this
26027 * @param {Roo.EventObject} e
26032 * Fires when the mouse exits this menu
26033 * @param {Roo.bootstrap.menu.Item} this
26034 * @param {Roo.EventObject} e
26040 * The raw click event for the entire grid.
26041 * @param {Roo.EventObject} e
26047 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26052 preventDefault: true,
26057 getAutoCreate : function()
26062 cls : 'roo-menu-item-text',
26070 cls : 'fa ' + this.icon
26079 href : this.href || '#',
26086 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26090 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26092 if(this.pos == 'left'){
26093 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26100 initEvents : function()
26102 this.el.on('mouseover', this.onMouseOver, this);
26103 this.el.on('mouseout', this.onMouseOut, this);
26105 this.el.select('a', true).first().on('click', this.onClick, this);
26109 onClick : function(e)
26111 if(this.preventDefault){
26112 e.preventDefault();
26115 this.fireEvent("click", this, e);
26118 onMouseOver : function(e)
26120 if(this.submenu && this.pos == 'left'){
26121 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26124 this.fireEvent("mouseover", this, e);
26127 onMouseOut : function(e)
26129 this.fireEvent("mouseout", this, e);
26141 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26144 * @class Roo.bootstrap.menu.Separator
26145 * @extends Roo.bootstrap.Component
26146 * Bootstrap Separator class
26149 * Create a new Separator
26150 * @param {Object} config The config object
26154 Roo.bootstrap.menu.Separator = function(config){
26155 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26158 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26160 getAutoCreate : function(){
26181 * @class Roo.bootstrap.Tooltip
26182 * Bootstrap Tooltip class
26183 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26184 * to determine which dom element triggers the tooltip.
26186 * It needs to add support for additional attributes like tooltip-position
26189 * Create a new Toolti
26190 * @param {Object} config The config object
26193 Roo.bootstrap.Tooltip = function(config){
26194 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26196 this.alignment = Roo.bootstrap.Tooltip.alignment;
26198 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26199 this.alignment = config.alignment;
26204 Roo.apply(Roo.bootstrap.Tooltip, {
26206 * @function init initialize tooltip monitoring.
26210 currentTip : false,
26211 currentRegion : false,
26217 Roo.get(document).on('mouseover', this.enter ,this);
26218 Roo.get(document).on('mouseout', this.leave, this);
26221 this.currentTip = new Roo.bootstrap.Tooltip();
26224 enter : function(ev)
26226 var dom = ev.getTarget();
26228 //Roo.log(['enter',dom]);
26229 var el = Roo.fly(dom);
26230 if (this.currentEl) {
26232 //Roo.log(this.currentEl);
26233 //Roo.log(this.currentEl.contains(dom));
26234 if (this.currentEl == el) {
26237 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26243 if (this.currentTip.el) {
26244 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26248 if(!el || el.dom == document){
26254 // you can not look for children, as if el is the body.. then everythign is the child..
26255 if (!el.attr('tooltip')) { //
26256 if (!el.select("[tooltip]").elements.length) {
26259 // is the mouse over this child...?
26260 bindEl = el.select("[tooltip]").first();
26261 var xy = ev.getXY();
26262 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26263 //Roo.log("not in region.");
26266 //Roo.log("child element over..");
26269 this.currentEl = bindEl;
26270 this.currentTip.bind(bindEl);
26271 this.currentRegion = Roo.lib.Region.getRegion(dom);
26272 this.currentTip.enter();
26275 leave : function(ev)
26277 var dom = ev.getTarget();
26278 //Roo.log(['leave',dom]);
26279 if (!this.currentEl) {
26284 if (dom != this.currentEl.dom) {
26287 var xy = ev.getXY();
26288 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26291 // only activate leave if mouse cursor is outside... bounding box..
26296 if (this.currentTip) {
26297 this.currentTip.leave();
26299 //Roo.log('clear currentEl');
26300 this.currentEl = false;
26305 'left' : ['r-l', [-2,0], 'right'],
26306 'right' : ['l-r', [2,0], 'left'],
26307 'bottom' : ['t-b', [0,2], 'top'],
26308 'top' : [ 'b-t', [0,-2], 'bottom']
26314 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26319 delay : null, // can be { show : 300 , hide: 500}
26323 hoverState : null, //???
26325 placement : 'bottom',
26329 getAutoCreate : function(){
26336 cls : 'tooltip-arrow'
26339 cls : 'tooltip-inner'
26346 bind : function(el)
26352 enter : function () {
26354 if (this.timeout != null) {
26355 clearTimeout(this.timeout);
26358 this.hoverState = 'in';
26359 //Roo.log("enter - show");
26360 if (!this.delay || !this.delay.show) {
26365 this.timeout = setTimeout(function () {
26366 if (_t.hoverState == 'in') {
26369 }, this.delay.show);
26373 clearTimeout(this.timeout);
26375 this.hoverState = 'out';
26376 if (!this.delay || !this.delay.hide) {
26382 this.timeout = setTimeout(function () {
26383 //Roo.log("leave - timeout");
26385 if (_t.hoverState == 'out') {
26387 Roo.bootstrap.Tooltip.currentEl = false;
26392 show : function (msg)
26395 this.render(document.body);
26398 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26400 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26402 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26404 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26406 var placement = typeof this.placement == 'function' ?
26407 this.placement.call(this, this.el, on_el) :
26410 var autoToken = /\s?auto?\s?/i;
26411 var autoPlace = autoToken.test(placement);
26413 placement = placement.replace(autoToken, '') || 'top';
26417 //this.el.setXY([0,0]);
26419 //this.el.dom.style.display='block';
26421 //this.el.appendTo(on_el);
26423 var p = this.getPosition();
26424 var box = this.el.getBox();
26430 var align = this.alignment[placement];
26432 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26434 if(placement == 'top' || placement == 'bottom'){
26436 placement = 'right';
26439 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26440 placement = 'left';
26443 var scroll = Roo.select('body', true).first().getScroll();
26445 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26449 align = this.alignment[placement];
26452 this.el.alignTo(this.bindEl, align[0],align[1]);
26453 //var arrow = this.el.select('.arrow',true).first();
26454 //arrow.set(align[2],
26456 this.el.addClass(placement);
26458 this.el.addClass('in fade');
26460 this.hoverState = null;
26462 if (this.el.hasClass('fade')) {
26473 //this.el.setXY([0,0]);
26474 this.el.removeClass('in');
26490 * @class Roo.bootstrap.LocationPicker
26491 * @extends Roo.bootstrap.Component
26492 * Bootstrap LocationPicker class
26493 * @cfg {Number} latitude Position when init default 0
26494 * @cfg {Number} longitude Position when init default 0
26495 * @cfg {Number} zoom default 15
26496 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26497 * @cfg {Boolean} mapTypeControl default false
26498 * @cfg {Boolean} disableDoubleClickZoom default false
26499 * @cfg {Boolean} scrollwheel default true
26500 * @cfg {Boolean} streetViewControl default false
26501 * @cfg {Number} radius default 0
26502 * @cfg {String} locationName
26503 * @cfg {Boolean} draggable default true
26504 * @cfg {Boolean} enableAutocomplete default false
26505 * @cfg {Boolean} enableReverseGeocode default true
26506 * @cfg {String} markerTitle
26509 * Create a new LocationPicker
26510 * @param {Object} config The config object
26514 Roo.bootstrap.LocationPicker = function(config){
26516 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26521 * Fires when the picker initialized.
26522 * @param {Roo.bootstrap.LocationPicker} this
26523 * @param {Google Location} location
26527 * @event positionchanged
26528 * Fires when the picker position changed.
26529 * @param {Roo.bootstrap.LocationPicker} this
26530 * @param {Google Location} location
26532 positionchanged : true,
26535 * Fires when the map resize.
26536 * @param {Roo.bootstrap.LocationPicker} this
26541 * Fires when the map show.
26542 * @param {Roo.bootstrap.LocationPicker} this
26547 * Fires when the map hide.
26548 * @param {Roo.bootstrap.LocationPicker} this
26553 * Fires when click the map.
26554 * @param {Roo.bootstrap.LocationPicker} this
26555 * @param {Map event} e
26559 * @event mapRightClick
26560 * Fires when right click the map.
26561 * @param {Roo.bootstrap.LocationPicker} this
26562 * @param {Map event} e
26564 mapRightClick : true,
26566 * @event markerClick
26567 * Fires when click the marker.
26568 * @param {Roo.bootstrap.LocationPicker} this
26569 * @param {Map event} e
26571 markerClick : true,
26573 * @event markerRightClick
26574 * Fires when right click the marker.
26575 * @param {Roo.bootstrap.LocationPicker} this
26576 * @param {Map event} e
26578 markerRightClick : true,
26580 * @event OverlayViewDraw
26581 * Fires when OverlayView Draw
26582 * @param {Roo.bootstrap.LocationPicker} this
26584 OverlayViewDraw : true,
26586 * @event OverlayViewOnAdd
26587 * Fires when OverlayView Draw
26588 * @param {Roo.bootstrap.LocationPicker} this
26590 OverlayViewOnAdd : true,
26592 * @event OverlayViewOnRemove
26593 * Fires when OverlayView Draw
26594 * @param {Roo.bootstrap.LocationPicker} this
26596 OverlayViewOnRemove : true,
26598 * @event OverlayViewShow
26599 * Fires when OverlayView Draw
26600 * @param {Roo.bootstrap.LocationPicker} this
26601 * @param {Pixel} cpx
26603 OverlayViewShow : true,
26605 * @event OverlayViewHide
26606 * Fires when OverlayView Draw
26607 * @param {Roo.bootstrap.LocationPicker} this
26609 OverlayViewHide : true,
26611 * @event loadexception
26612 * Fires when load google lib failed.
26613 * @param {Roo.bootstrap.LocationPicker} this
26615 loadexception : true
26620 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26622 gMapContext: false,
26628 mapTypeControl: false,
26629 disableDoubleClickZoom: false,
26631 streetViewControl: false,
26635 enableAutocomplete: false,
26636 enableReverseGeocode: true,
26639 getAutoCreate: function()
26644 cls: 'roo-location-picker'
26650 initEvents: function(ct, position)
26652 if(!this.el.getWidth() || this.isApplied()){
26656 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26661 initial: function()
26663 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26664 this.fireEvent('loadexception', this);
26668 if(!this.mapTypeId){
26669 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26672 this.gMapContext = this.GMapContext();
26674 this.initOverlayView();
26676 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26680 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26681 _this.setPosition(_this.gMapContext.marker.position);
26684 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26685 _this.fireEvent('mapClick', this, event);
26689 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26690 _this.fireEvent('mapRightClick', this, event);
26694 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26695 _this.fireEvent('markerClick', this, event);
26699 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26700 _this.fireEvent('markerRightClick', this, event);
26704 this.setPosition(this.gMapContext.location);
26706 this.fireEvent('initial', this, this.gMapContext.location);
26709 initOverlayView: function()
26713 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26717 _this.fireEvent('OverlayViewDraw', _this);
26722 _this.fireEvent('OverlayViewOnAdd', _this);
26725 onRemove: function()
26727 _this.fireEvent('OverlayViewOnRemove', _this);
26730 show: function(cpx)
26732 _this.fireEvent('OverlayViewShow', _this, cpx);
26737 _this.fireEvent('OverlayViewHide', _this);
26743 fromLatLngToContainerPixel: function(event)
26745 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26748 isApplied: function()
26750 return this.getGmapContext() == false ? false : true;
26753 getGmapContext: function()
26755 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26758 GMapContext: function()
26760 var position = new google.maps.LatLng(this.latitude, this.longitude);
26762 var _map = new google.maps.Map(this.el.dom, {
26765 mapTypeId: this.mapTypeId,
26766 mapTypeControl: this.mapTypeControl,
26767 disableDoubleClickZoom: this.disableDoubleClickZoom,
26768 scrollwheel: this.scrollwheel,
26769 streetViewControl: this.streetViewControl,
26770 locationName: this.locationName,
26771 draggable: this.draggable,
26772 enableAutocomplete: this.enableAutocomplete,
26773 enableReverseGeocode: this.enableReverseGeocode
26776 var _marker = new google.maps.Marker({
26777 position: position,
26779 title: this.markerTitle,
26780 draggable: this.draggable
26787 location: position,
26788 radius: this.radius,
26789 locationName: this.locationName,
26790 addressComponents: {
26791 formatted_address: null,
26792 addressLine1: null,
26793 addressLine2: null,
26795 streetNumber: null,
26799 stateOrProvince: null
26802 domContainer: this.el.dom,
26803 geodecoder: new google.maps.Geocoder()
26807 drawCircle: function(center, radius, options)
26809 if (this.gMapContext.circle != null) {
26810 this.gMapContext.circle.setMap(null);
26814 options = Roo.apply({}, options, {
26815 strokeColor: "#0000FF",
26816 strokeOpacity: .35,
26818 fillColor: "#0000FF",
26822 options.map = this.gMapContext.map;
26823 options.radius = radius;
26824 options.center = center;
26825 this.gMapContext.circle = new google.maps.Circle(options);
26826 return this.gMapContext.circle;
26832 setPosition: function(location)
26834 this.gMapContext.location = location;
26835 this.gMapContext.marker.setPosition(location);
26836 this.gMapContext.map.panTo(location);
26837 this.drawCircle(location, this.gMapContext.radius, {});
26841 if (this.gMapContext.settings.enableReverseGeocode) {
26842 this.gMapContext.geodecoder.geocode({
26843 latLng: this.gMapContext.location
26844 }, function(results, status) {
26846 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26847 _this.gMapContext.locationName = results[0].formatted_address;
26848 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26850 _this.fireEvent('positionchanged', this, location);
26857 this.fireEvent('positionchanged', this, location);
26862 google.maps.event.trigger(this.gMapContext.map, "resize");
26864 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26866 this.fireEvent('resize', this);
26869 setPositionByLatLng: function(latitude, longitude)
26871 this.setPosition(new google.maps.LatLng(latitude, longitude));
26874 getCurrentPosition: function()
26877 latitude: this.gMapContext.location.lat(),
26878 longitude: this.gMapContext.location.lng()
26882 getAddressName: function()
26884 return this.gMapContext.locationName;
26887 getAddressComponents: function()
26889 return this.gMapContext.addressComponents;
26892 address_component_from_google_geocode: function(address_components)
26896 for (var i = 0; i < address_components.length; i++) {
26897 var component = address_components[i];
26898 if (component.types.indexOf("postal_code") >= 0) {
26899 result.postalCode = component.short_name;
26900 } else if (component.types.indexOf("street_number") >= 0) {
26901 result.streetNumber = component.short_name;
26902 } else if (component.types.indexOf("route") >= 0) {
26903 result.streetName = component.short_name;
26904 } else if (component.types.indexOf("neighborhood") >= 0) {
26905 result.city = component.short_name;
26906 } else if (component.types.indexOf("locality") >= 0) {
26907 result.city = component.short_name;
26908 } else if (component.types.indexOf("sublocality") >= 0) {
26909 result.district = component.short_name;
26910 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26911 result.stateOrProvince = component.short_name;
26912 } else if (component.types.indexOf("country") >= 0) {
26913 result.country = component.short_name;
26917 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26918 result.addressLine2 = "";
26922 setZoomLevel: function(zoom)
26924 this.gMapContext.map.setZoom(zoom);
26937 this.fireEvent('show', this);
26948 this.fireEvent('hide', this);
26953 Roo.apply(Roo.bootstrap.LocationPicker, {
26955 OverlayView : function(map, options)
26957 options = options || {};
26971 * @class Roo.bootstrap.Alert
26972 * @extends Roo.bootstrap.Component
26973 * Bootstrap Alert class
26974 * @cfg {String} title The title of alert
26975 * @cfg {String} html The content of alert
26976 * @cfg {String} weight ( success | info | warning | danger )
26977 * @cfg {String} faicon font-awesomeicon
26980 * Create a new alert
26981 * @param {Object} config The config object
26985 Roo.bootstrap.Alert = function(config){
26986 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26990 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26997 getAutoCreate : function()
27006 cls : 'roo-alert-icon'
27011 cls : 'roo-alert-title',
27016 cls : 'roo-alert-text',
27023 cfg.cn[0].cls += ' fa ' + this.faicon;
27027 cfg.cls += ' alert-' + this.weight;
27033 initEvents: function()
27035 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27038 setTitle : function(str)
27040 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27043 setText : function(str)
27045 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27048 setWeight : function(weight)
27051 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27054 this.weight = weight;
27056 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27059 setIcon : function(icon)
27062 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27065 this.faicon = icon;
27067 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27088 * @class Roo.bootstrap.UploadCropbox
27089 * @extends Roo.bootstrap.Component
27090 * Bootstrap UploadCropbox class
27091 * @cfg {String} emptyText show when image has been loaded
27092 * @cfg {String} rotateNotify show when image too small to rotate
27093 * @cfg {Number} errorTimeout default 3000
27094 * @cfg {Number} minWidth default 300
27095 * @cfg {Number} minHeight default 300
27096 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27097 * @cfg {Boolean} isDocument (true|false) default false
27098 * @cfg {String} url action url
27099 * @cfg {String} paramName default 'imageUpload'
27100 * @cfg {String} method default POST
27101 * @cfg {Boolean} loadMask (true|false) default true
27102 * @cfg {Boolean} loadingText default 'Loading...'
27105 * Create a new UploadCropbox
27106 * @param {Object} config The config object
27109 Roo.bootstrap.UploadCropbox = function(config){
27110 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27114 * @event beforeselectfile
27115 * Fire before select file
27116 * @param {Roo.bootstrap.UploadCropbox} this
27118 "beforeselectfile" : true,
27121 * Fire after initEvent
27122 * @param {Roo.bootstrap.UploadCropbox} this
27127 * Fire after initEvent
27128 * @param {Roo.bootstrap.UploadCropbox} this
27129 * @param {String} data
27134 * Fire when preparing the file data
27135 * @param {Roo.bootstrap.UploadCropbox} this
27136 * @param {Object} file
27141 * Fire when get exception
27142 * @param {Roo.bootstrap.UploadCropbox} this
27143 * @param {XMLHttpRequest} xhr
27145 "exception" : true,
27147 * @event beforeloadcanvas
27148 * Fire before load the canvas
27149 * @param {Roo.bootstrap.UploadCropbox} this
27150 * @param {String} src
27152 "beforeloadcanvas" : true,
27155 * Fire when trash image
27156 * @param {Roo.bootstrap.UploadCropbox} this
27161 * Fire when download the image
27162 * @param {Roo.bootstrap.UploadCropbox} this
27166 * @event footerbuttonclick
27167 * Fire when footerbuttonclick
27168 * @param {Roo.bootstrap.UploadCropbox} this
27169 * @param {String} type
27171 "footerbuttonclick" : true,
27175 * @param {Roo.bootstrap.UploadCropbox} this
27180 * Fire when rotate the image
27181 * @param {Roo.bootstrap.UploadCropbox} this
27182 * @param {String} pos
27187 * Fire when inspect the file
27188 * @param {Roo.bootstrap.UploadCropbox} this
27189 * @param {Object} file
27194 * Fire when xhr upload the file
27195 * @param {Roo.bootstrap.UploadCropbox} this
27196 * @param {Object} data
27201 * Fire when arrange the file data
27202 * @param {Roo.bootstrap.UploadCropbox} this
27203 * @param {Object} formData
27208 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27211 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27213 emptyText : 'Click to upload image',
27214 rotateNotify : 'Image is too small to rotate',
27215 errorTimeout : 3000,
27229 cropType : 'image/jpeg',
27231 canvasLoaded : false,
27232 isDocument : false,
27234 paramName : 'imageUpload',
27236 loadingText : 'Loading...',
27239 getAutoCreate : function()
27243 cls : 'roo-upload-cropbox',
27247 cls : 'roo-upload-cropbox-selector',
27252 cls : 'roo-upload-cropbox-body',
27253 style : 'cursor:pointer',
27257 cls : 'roo-upload-cropbox-preview'
27261 cls : 'roo-upload-cropbox-thumb'
27265 cls : 'roo-upload-cropbox-empty-notify',
27266 html : this.emptyText
27270 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27271 html : this.rotateNotify
27277 cls : 'roo-upload-cropbox-footer',
27280 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27290 onRender : function(ct, position)
27292 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27294 if (this.buttons.length) {
27296 Roo.each(this.buttons, function(bb) {
27298 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27300 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27306 this.maskEl = this.el;
27310 initEvents : function()
27312 this.urlAPI = (window.createObjectURL && window) ||
27313 (window.URL && URL.revokeObjectURL && URL) ||
27314 (window.webkitURL && webkitURL);
27316 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27317 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27319 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27320 this.selectorEl.hide();
27322 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27323 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27325 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27326 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27327 this.thumbEl.hide();
27329 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27330 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27332 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27333 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27334 this.errorEl.hide();
27336 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27337 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27338 this.footerEl.hide();
27340 this.setThumbBoxSize();
27346 this.fireEvent('initial', this);
27353 window.addEventListener("resize", function() { _this.resize(); } );
27355 this.bodyEl.on('click', this.beforeSelectFile, this);
27358 this.bodyEl.on('touchstart', this.onTouchStart, this);
27359 this.bodyEl.on('touchmove', this.onTouchMove, this);
27360 this.bodyEl.on('touchend', this.onTouchEnd, this);
27364 this.bodyEl.on('mousedown', this.onMouseDown, this);
27365 this.bodyEl.on('mousemove', this.onMouseMove, this);
27366 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27367 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27368 Roo.get(document).on('mouseup', this.onMouseUp, this);
27371 this.selectorEl.on('change', this.onFileSelected, this);
27377 this.baseScale = 1;
27379 this.baseRotate = 1;
27380 this.dragable = false;
27381 this.pinching = false;
27384 this.cropData = false;
27385 this.notifyEl.dom.innerHTML = this.emptyText;
27387 this.selectorEl.dom.value = '';
27391 resize : function()
27393 if(this.fireEvent('resize', this) != false){
27394 this.setThumbBoxPosition();
27395 this.setCanvasPosition();
27399 onFooterButtonClick : function(e, el, o, type)
27402 case 'rotate-left' :
27403 this.onRotateLeft(e);
27405 case 'rotate-right' :
27406 this.onRotateRight(e);
27409 this.beforeSelectFile(e);
27424 this.fireEvent('footerbuttonclick', this, type);
27427 beforeSelectFile : function(e)
27429 e.preventDefault();
27431 if(this.fireEvent('beforeselectfile', this) != false){
27432 this.selectorEl.dom.click();
27436 onFileSelected : function(e)
27438 e.preventDefault();
27440 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27444 var file = this.selectorEl.dom.files[0];
27446 if(this.fireEvent('inspect', this, file) != false){
27447 this.prepare(file);
27452 trash : function(e)
27454 this.fireEvent('trash', this);
27457 download : function(e)
27459 this.fireEvent('download', this);
27462 loadCanvas : function(src)
27464 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27468 this.imageEl = document.createElement('img');
27472 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27474 this.imageEl.src = src;
27478 onLoadCanvas : function()
27480 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27481 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27483 this.bodyEl.un('click', this.beforeSelectFile, this);
27485 this.notifyEl.hide();
27486 this.thumbEl.show();
27487 this.footerEl.show();
27489 this.baseRotateLevel();
27491 if(this.isDocument){
27492 this.setThumbBoxSize();
27495 this.setThumbBoxPosition();
27497 this.baseScaleLevel();
27503 this.canvasLoaded = true;
27506 this.maskEl.unmask();
27511 setCanvasPosition : function()
27513 if(!this.canvasEl){
27517 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27518 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27520 this.previewEl.setLeft(pw);
27521 this.previewEl.setTop(ph);
27525 onMouseDown : function(e)
27529 this.dragable = true;
27530 this.pinching = false;
27532 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27533 this.dragable = false;
27537 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27538 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27542 onMouseMove : function(e)
27546 if(!this.canvasLoaded){
27550 if (!this.dragable){
27554 var minX = Math.ceil(this.thumbEl.getLeft(true));
27555 var minY = Math.ceil(this.thumbEl.getTop(true));
27557 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27558 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27560 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27561 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27563 x = x - this.mouseX;
27564 y = y - this.mouseY;
27566 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27567 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27569 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27570 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27572 this.previewEl.setLeft(bgX);
27573 this.previewEl.setTop(bgY);
27575 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27576 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27579 onMouseUp : function(e)
27583 this.dragable = false;
27586 onMouseWheel : function(e)
27590 this.startScale = this.scale;
27592 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27594 if(!this.zoomable()){
27595 this.scale = this.startScale;
27604 zoomable : function()
27606 var minScale = this.thumbEl.getWidth() / this.minWidth;
27608 if(this.minWidth < this.minHeight){
27609 minScale = this.thumbEl.getHeight() / this.minHeight;
27612 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27613 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27617 (this.rotate == 0 || this.rotate == 180) &&
27619 width > this.imageEl.OriginWidth ||
27620 height > this.imageEl.OriginHeight ||
27621 (width < this.minWidth && height < this.minHeight)
27629 (this.rotate == 90 || this.rotate == 270) &&
27631 width > this.imageEl.OriginWidth ||
27632 height > this.imageEl.OriginHeight ||
27633 (width < this.minHeight && height < this.minWidth)
27640 !this.isDocument &&
27641 (this.rotate == 0 || this.rotate == 180) &&
27643 width < this.minWidth ||
27644 width > this.imageEl.OriginWidth ||
27645 height < this.minHeight ||
27646 height > this.imageEl.OriginHeight
27653 !this.isDocument &&
27654 (this.rotate == 90 || this.rotate == 270) &&
27656 width < this.minHeight ||
27657 width > this.imageEl.OriginWidth ||
27658 height < this.minWidth ||
27659 height > this.imageEl.OriginHeight
27669 onRotateLeft : function(e)
27671 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27673 var minScale = this.thumbEl.getWidth() / this.minWidth;
27675 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27676 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27678 this.startScale = this.scale;
27680 while (this.getScaleLevel() < minScale){
27682 this.scale = this.scale + 1;
27684 if(!this.zoomable()){
27689 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27690 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27695 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27702 this.scale = this.startScale;
27704 this.onRotateFail();
27709 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27711 if(this.isDocument){
27712 this.setThumbBoxSize();
27713 this.setThumbBoxPosition();
27714 this.setCanvasPosition();
27719 this.fireEvent('rotate', this, 'left');
27723 onRotateRight : function(e)
27725 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27727 var minScale = this.thumbEl.getWidth() / this.minWidth;
27729 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27730 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27732 this.startScale = this.scale;
27734 while (this.getScaleLevel() < minScale){
27736 this.scale = this.scale + 1;
27738 if(!this.zoomable()){
27743 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27744 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27749 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27756 this.scale = this.startScale;
27758 this.onRotateFail();
27763 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27765 if(this.isDocument){
27766 this.setThumbBoxSize();
27767 this.setThumbBoxPosition();
27768 this.setCanvasPosition();
27773 this.fireEvent('rotate', this, 'right');
27776 onRotateFail : function()
27778 this.errorEl.show(true);
27782 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27787 this.previewEl.dom.innerHTML = '';
27789 var canvasEl = document.createElement("canvas");
27791 var contextEl = canvasEl.getContext("2d");
27793 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27794 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27795 var center = this.imageEl.OriginWidth / 2;
27797 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27798 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27799 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27800 center = this.imageEl.OriginHeight / 2;
27803 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27805 contextEl.translate(center, center);
27806 contextEl.rotate(this.rotate * Math.PI / 180);
27808 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27810 this.canvasEl = document.createElement("canvas");
27812 this.contextEl = this.canvasEl.getContext("2d");
27814 switch (this.rotate) {
27817 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27818 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27820 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27825 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27826 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27828 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27829 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);
27833 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27838 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27839 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27841 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27842 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);
27846 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);
27851 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27852 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27854 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27855 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27859 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);
27866 this.previewEl.appendChild(this.canvasEl);
27868 this.setCanvasPosition();
27873 if(!this.canvasLoaded){
27877 var imageCanvas = document.createElement("canvas");
27879 var imageContext = imageCanvas.getContext("2d");
27881 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27882 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27884 var center = imageCanvas.width / 2;
27886 imageContext.translate(center, center);
27888 imageContext.rotate(this.rotate * Math.PI / 180);
27890 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27892 var canvas = document.createElement("canvas");
27894 var context = canvas.getContext("2d");
27896 canvas.width = this.minWidth;
27897 canvas.height = this.minHeight;
27899 switch (this.rotate) {
27902 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27903 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27905 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27906 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27908 var targetWidth = this.minWidth - 2 * x;
27909 var targetHeight = this.minHeight - 2 * y;
27913 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27914 scale = targetWidth / width;
27917 if(x > 0 && y == 0){
27918 scale = targetHeight / height;
27921 if(x > 0 && y > 0){
27922 scale = targetWidth / width;
27924 if(width < height){
27925 scale = targetHeight / height;
27929 context.scale(scale, scale);
27931 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27932 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27934 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27935 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27937 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27942 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27943 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27945 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27946 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27948 var targetWidth = this.minWidth - 2 * x;
27949 var targetHeight = this.minHeight - 2 * y;
27953 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27954 scale = targetWidth / width;
27957 if(x > 0 && y == 0){
27958 scale = targetHeight / height;
27961 if(x > 0 && y > 0){
27962 scale = targetWidth / width;
27964 if(width < height){
27965 scale = targetHeight / height;
27969 context.scale(scale, scale);
27971 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27972 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27974 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27975 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27977 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27979 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27984 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27985 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27987 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27988 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27990 var targetWidth = this.minWidth - 2 * x;
27991 var targetHeight = this.minHeight - 2 * y;
27995 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27996 scale = targetWidth / width;
27999 if(x > 0 && y == 0){
28000 scale = targetHeight / height;
28003 if(x > 0 && y > 0){
28004 scale = targetWidth / width;
28006 if(width < height){
28007 scale = targetHeight / height;
28011 context.scale(scale, scale);
28013 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28014 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28016 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28017 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28019 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28020 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28022 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28027 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28028 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28030 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28031 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28033 var targetWidth = this.minWidth - 2 * x;
28034 var targetHeight = this.minHeight - 2 * y;
28038 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28039 scale = targetWidth / width;
28042 if(x > 0 && y == 0){
28043 scale = targetHeight / height;
28046 if(x > 0 && y > 0){
28047 scale = targetWidth / width;
28049 if(width < height){
28050 scale = targetHeight / height;
28054 context.scale(scale, scale);
28056 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28057 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28059 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28060 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28062 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28064 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28071 this.cropData = canvas.toDataURL(this.cropType);
28073 if(this.fireEvent('crop', this, this.cropData) !== false){
28074 this.process(this.file, this.cropData);
28081 setThumbBoxSize : function()
28085 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28086 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28087 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28089 this.minWidth = width;
28090 this.minHeight = height;
28092 if(this.rotate == 90 || this.rotate == 270){
28093 this.minWidth = height;
28094 this.minHeight = width;
28099 width = Math.ceil(this.minWidth * height / this.minHeight);
28101 if(this.minWidth > this.minHeight){
28103 height = Math.ceil(this.minHeight * width / this.minWidth);
28106 this.thumbEl.setStyle({
28107 width : width + 'px',
28108 height : height + 'px'
28115 setThumbBoxPosition : function()
28117 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28118 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28120 this.thumbEl.setLeft(x);
28121 this.thumbEl.setTop(y);
28125 baseRotateLevel : function()
28127 this.baseRotate = 1;
28130 typeof(this.exif) != 'undefined' &&
28131 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28132 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28134 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28137 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28141 baseScaleLevel : function()
28145 if(this.isDocument){
28147 if(this.baseRotate == 6 || this.baseRotate == 8){
28149 height = this.thumbEl.getHeight();
28150 this.baseScale = height / this.imageEl.OriginWidth;
28152 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28153 width = this.thumbEl.getWidth();
28154 this.baseScale = width / this.imageEl.OriginHeight;
28160 height = this.thumbEl.getHeight();
28161 this.baseScale = height / this.imageEl.OriginHeight;
28163 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28164 width = this.thumbEl.getWidth();
28165 this.baseScale = width / this.imageEl.OriginWidth;
28171 if(this.baseRotate == 6 || this.baseRotate == 8){
28173 width = this.thumbEl.getHeight();
28174 this.baseScale = width / this.imageEl.OriginHeight;
28176 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28177 height = this.thumbEl.getWidth();
28178 this.baseScale = height / this.imageEl.OriginHeight;
28181 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28182 height = this.thumbEl.getWidth();
28183 this.baseScale = height / this.imageEl.OriginHeight;
28185 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28186 width = this.thumbEl.getHeight();
28187 this.baseScale = width / this.imageEl.OriginWidth;
28194 width = this.thumbEl.getWidth();
28195 this.baseScale = width / this.imageEl.OriginWidth;
28197 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28198 height = this.thumbEl.getHeight();
28199 this.baseScale = height / this.imageEl.OriginHeight;
28202 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28204 height = this.thumbEl.getHeight();
28205 this.baseScale = height / this.imageEl.OriginHeight;
28207 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28208 width = this.thumbEl.getWidth();
28209 this.baseScale = width / this.imageEl.OriginWidth;
28217 getScaleLevel : function()
28219 return this.baseScale * Math.pow(1.1, this.scale);
28222 onTouchStart : function(e)
28224 if(!this.canvasLoaded){
28225 this.beforeSelectFile(e);
28229 var touches = e.browserEvent.touches;
28235 if(touches.length == 1){
28236 this.onMouseDown(e);
28240 if(touches.length != 2){
28246 for(var i = 0, finger; finger = touches[i]; i++){
28247 coords.push(finger.pageX, finger.pageY);
28250 var x = Math.pow(coords[0] - coords[2], 2);
28251 var y = Math.pow(coords[1] - coords[3], 2);
28253 this.startDistance = Math.sqrt(x + y);
28255 this.startScale = this.scale;
28257 this.pinching = true;
28258 this.dragable = false;
28262 onTouchMove : function(e)
28264 if(!this.pinching && !this.dragable){
28268 var touches = e.browserEvent.touches;
28275 this.onMouseMove(e);
28281 for(var i = 0, finger; finger = touches[i]; i++){
28282 coords.push(finger.pageX, finger.pageY);
28285 var x = Math.pow(coords[0] - coords[2], 2);
28286 var y = Math.pow(coords[1] - coords[3], 2);
28288 this.endDistance = Math.sqrt(x + y);
28290 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28292 if(!this.zoomable()){
28293 this.scale = this.startScale;
28301 onTouchEnd : function(e)
28303 this.pinching = false;
28304 this.dragable = false;
28308 process : function(file, crop)
28311 this.maskEl.mask(this.loadingText);
28314 this.xhr = new XMLHttpRequest();
28316 file.xhr = this.xhr;
28318 this.xhr.open(this.method, this.url, true);
28321 "Accept": "application/json",
28322 "Cache-Control": "no-cache",
28323 "X-Requested-With": "XMLHttpRequest"
28326 for (var headerName in headers) {
28327 var headerValue = headers[headerName];
28329 this.xhr.setRequestHeader(headerName, headerValue);
28335 this.xhr.onload = function()
28337 _this.xhrOnLoad(_this.xhr);
28340 this.xhr.onerror = function()
28342 _this.xhrOnError(_this.xhr);
28345 var formData = new FormData();
28347 formData.append('returnHTML', 'NO');
28350 formData.append('crop', crop);
28353 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28354 formData.append(this.paramName, file, file.name);
28357 if(typeof(file.filename) != 'undefined'){
28358 formData.append('filename', file.filename);
28361 if(typeof(file.mimetype) != 'undefined'){
28362 formData.append('mimetype', file.mimetype);
28365 if(this.fireEvent('arrange', this, formData) != false){
28366 this.xhr.send(formData);
28370 xhrOnLoad : function(xhr)
28373 this.maskEl.unmask();
28376 if (xhr.readyState !== 4) {
28377 this.fireEvent('exception', this, xhr);
28381 var response = Roo.decode(xhr.responseText);
28383 if(!response.success){
28384 this.fireEvent('exception', this, xhr);
28388 var response = Roo.decode(xhr.responseText);
28390 this.fireEvent('upload', this, response);
28394 xhrOnError : function()
28397 this.maskEl.unmask();
28400 Roo.log('xhr on error');
28402 var response = Roo.decode(xhr.responseText);
28408 prepare : function(file)
28411 this.maskEl.mask(this.loadingText);
28417 if(typeof(file) === 'string'){
28418 this.loadCanvas(file);
28422 if(!file || !this.urlAPI){
28427 this.cropType = file.type;
28431 if(this.fireEvent('prepare', this, this.file) != false){
28433 var reader = new FileReader();
28435 reader.onload = function (e) {
28436 if (e.target.error) {
28437 Roo.log(e.target.error);
28441 var buffer = e.target.result,
28442 dataView = new DataView(buffer),
28444 maxOffset = dataView.byteLength - 4,
28448 if (dataView.getUint16(0) === 0xffd8) {
28449 while (offset < maxOffset) {
28450 markerBytes = dataView.getUint16(offset);
28452 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28453 markerLength = dataView.getUint16(offset + 2) + 2;
28454 if (offset + markerLength > dataView.byteLength) {
28455 Roo.log('Invalid meta data: Invalid segment size.');
28459 if(markerBytes == 0xffe1){
28460 _this.parseExifData(
28467 offset += markerLength;
28477 var url = _this.urlAPI.createObjectURL(_this.file);
28479 _this.loadCanvas(url);
28484 reader.readAsArrayBuffer(this.file);
28490 parseExifData : function(dataView, offset, length)
28492 var tiffOffset = offset + 10,
28496 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28497 // No Exif data, might be XMP data instead
28501 // Check for the ASCII code for "Exif" (0x45786966):
28502 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28503 // No Exif data, might be XMP data instead
28506 if (tiffOffset + 8 > dataView.byteLength) {
28507 Roo.log('Invalid Exif data: Invalid segment size.');
28510 // Check for the two null bytes:
28511 if (dataView.getUint16(offset + 8) !== 0x0000) {
28512 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28515 // Check the byte alignment:
28516 switch (dataView.getUint16(tiffOffset)) {
28518 littleEndian = true;
28521 littleEndian = false;
28524 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28527 // Check for the TIFF tag marker (0x002A):
28528 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28529 Roo.log('Invalid Exif data: Missing TIFF marker.');
28532 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28533 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28535 this.parseExifTags(
28538 tiffOffset + dirOffset,
28543 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28548 if (dirOffset + 6 > dataView.byteLength) {
28549 Roo.log('Invalid Exif data: Invalid directory offset.');
28552 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28553 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28554 if (dirEndOffset + 4 > dataView.byteLength) {
28555 Roo.log('Invalid Exif data: Invalid directory size.');
28558 for (i = 0; i < tagsNumber; i += 1) {
28562 dirOffset + 2 + 12 * i, // tag offset
28566 // Return the offset to the next directory:
28567 return dataView.getUint32(dirEndOffset, littleEndian);
28570 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28572 var tag = dataView.getUint16(offset, littleEndian);
28574 this.exif[tag] = this.getExifValue(
28578 dataView.getUint16(offset + 2, littleEndian), // tag type
28579 dataView.getUint32(offset + 4, littleEndian), // tag length
28584 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28586 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28595 Roo.log('Invalid Exif data: Invalid tag type.');
28599 tagSize = tagType.size * length;
28600 // Determine if the value is contained in the dataOffset bytes,
28601 // or if the value at the dataOffset is a pointer to the actual data:
28602 dataOffset = tagSize > 4 ?
28603 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28604 if (dataOffset + tagSize > dataView.byteLength) {
28605 Roo.log('Invalid Exif data: Invalid data offset.');
28608 if (length === 1) {
28609 return tagType.getValue(dataView, dataOffset, littleEndian);
28612 for (i = 0; i < length; i += 1) {
28613 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28616 if (tagType.ascii) {
28618 // Concatenate the chars:
28619 for (i = 0; i < values.length; i += 1) {
28621 // Ignore the terminating NULL byte(s):
28622 if (c === '\u0000') {
28634 Roo.apply(Roo.bootstrap.UploadCropbox, {
28636 'Orientation': 0x0112
28640 1: 0, //'top-left',
28642 3: 180, //'bottom-right',
28643 // 4: 'bottom-left',
28645 6: 90, //'right-top',
28646 // 7: 'right-bottom',
28647 8: 270 //'left-bottom'
28651 // byte, 8-bit unsigned int:
28653 getValue: function (dataView, dataOffset) {
28654 return dataView.getUint8(dataOffset);
28658 // ascii, 8-bit byte:
28660 getValue: function (dataView, dataOffset) {
28661 return String.fromCharCode(dataView.getUint8(dataOffset));
28666 // short, 16 bit int:
28668 getValue: function (dataView, dataOffset, littleEndian) {
28669 return dataView.getUint16(dataOffset, littleEndian);
28673 // long, 32 bit int:
28675 getValue: function (dataView, dataOffset, littleEndian) {
28676 return dataView.getUint32(dataOffset, littleEndian);
28680 // rational = two long values, first is numerator, second is denominator:
28682 getValue: function (dataView, dataOffset, littleEndian) {
28683 return dataView.getUint32(dataOffset, littleEndian) /
28684 dataView.getUint32(dataOffset + 4, littleEndian);
28688 // slong, 32 bit signed int:
28690 getValue: function (dataView, dataOffset, littleEndian) {
28691 return dataView.getInt32(dataOffset, littleEndian);
28695 // srational, two slongs, first is numerator, second is denominator:
28697 getValue: function (dataView, dataOffset, littleEndian) {
28698 return dataView.getInt32(dataOffset, littleEndian) /
28699 dataView.getInt32(dataOffset + 4, littleEndian);
28709 cls : 'btn-group roo-upload-cropbox-rotate-left',
28710 action : 'rotate-left',
28714 cls : 'btn btn-default',
28715 html : '<i class="fa fa-undo"></i>'
28721 cls : 'btn-group roo-upload-cropbox-picture',
28722 action : 'picture',
28726 cls : 'btn btn-default',
28727 html : '<i class="fa fa-picture-o"></i>'
28733 cls : 'btn-group roo-upload-cropbox-rotate-right',
28734 action : 'rotate-right',
28738 cls : 'btn btn-default',
28739 html : '<i class="fa fa-repeat"></i>'
28747 cls : 'btn-group roo-upload-cropbox-rotate-left',
28748 action : 'rotate-left',
28752 cls : 'btn btn-default',
28753 html : '<i class="fa fa-undo"></i>'
28759 cls : 'btn-group roo-upload-cropbox-download',
28760 action : 'download',
28764 cls : 'btn btn-default',
28765 html : '<i class="fa fa-download"></i>'
28771 cls : 'btn-group roo-upload-cropbox-crop',
28776 cls : 'btn btn-default',
28777 html : '<i class="fa fa-crop"></i>'
28783 cls : 'btn-group roo-upload-cropbox-trash',
28788 cls : 'btn btn-default',
28789 html : '<i class="fa fa-trash"></i>'
28795 cls : 'btn-group roo-upload-cropbox-rotate-right',
28796 action : 'rotate-right',
28800 cls : 'btn btn-default',
28801 html : '<i class="fa fa-repeat"></i>'
28809 cls : 'btn-group roo-upload-cropbox-rotate-left',
28810 action : 'rotate-left',
28814 cls : 'btn btn-default',
28815 html : '<i class="fa fa-undo"></i>'
28821 cls : 'btn-group roo-upload-cropbox-rotate-right',
28822 action : 'rotate-right',
28826 cls : 'btn btn-default',
28827 html : '<i class="fa fa-repeat"></i>'
28840 * @class Roo.bootstrap.DocumentManager
28841 * @extends Roo.bootstrap.Component
28842 * Bootstrap DocumentManager class
28843 * @cfg {String} paramName default 'imageUpload'
28844 * @cfg {String} toolTipName default 'filename'
28845 * @cfg {String} method default POST
28846 * @cfg {String} url action url
28847 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28848 * @cfg {Boolean} multiple multiple upload default true
28849 * @cfg {Number} thumbSize default 300
28850 * @cfg {String} fieldLabel
28851 * @cfg {Number} labelWidth default 4
28852 * @cfg {String} labelAlign (left|top) default left
28853 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28854 * @cfg {Number} labellg set the width of label (1-12)
28855 * @cfg {Number} labelmd set the width of label (1-12)
28856 * @cfg {Number} labelsm set the width of label (1-12)
28857 * @cfg {Number} labelxs set the width of label (1-12)
28860 * Create a new DocumentManager
28861 * @param {Object} config The config object
28864 Roo.bootstrap.DocumentManager = function(config){
28865 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28868 this.delegates = [];
28873 * Fire when initial the DocumentManager
28874 * @param {Roo.bootstrap.DocumentManager} this
28879 * inspect selected file
28880 * @param {Roo.bootstrap.DocumentManager} this
28881 * @param {File} file
28886 * Fire when xhr load exception
28887 * @param {Roo.bootstrap.DocumentManager} this
28888 * @param {XMLHttpRequest} xhr
28890 "exception" : true,
28892 * @event afterupload
28893 * Fire when xhr load exception
28894 * @param {Roo.bootstrap.DocumentManager} this
28895 * @param {XMLHttpRequest} xhr
28897 "afterupload" : true,
28900 * prepare the form data
28901 * @param {Roo.bootstrap.DocumentManager} this
28902 * @param {Object} formData
28907 * Fire when remove the file
28908 * @param {Roo.bootstrap.DocumentManager} this
28909 * @param {Object} file
28914 * Fire after refresh the file
28915 * @param {Roo.bootstrap.DocumentManager} this
28920 * Fire after click the image
28921 * @param {Roo.bootstrap.DocumentManager} this
28922 * @param {Object} file
28927 * Fire when upload a image and editable set to true
28928 * @param {Roo.bootstrap.DocumentManager} this
28929 * @param {Object} file
28933 * @event beforeselectfile
28934 * Fire before select file
28935 * @param {Roo.bootstrap.DocumentManager} this
28937 "beforeselectfile" : true,
28940 * Fire before process file
28941 * @param {Roo.bootstrap.DocumentManager} this
28942 * @param {Object} file
28946 * @event previewrendered
28947 * Fire when preview rendered
28948 * @param {Roo.bootstrap.DocumentManager} this
28949 * @param {Object} file
28951 "previewrendered" : true,
28954 "previewResize" : true
28959 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28968 paramName : 'imageUpload',
28969 toolTipName : 'filename',
28972 labelAlign : 'left',
28982 getAutoCreate : function()
28984 var managerWidget = {
28986 cls : 'roo-document-manager',
28990 cls : 'roo-document-manager-selector',
28995 cls : 'roo-document-manager-uploader',
28999 cls : 'roo-document-manager-upload-btn',
29000 html : '<i class="fa fa-plus"></i>'
29011 cls : 'column col-md-12',
29016 if(this.fieldLabel.length){
29021 cls : 'column col-md-12',
29022 html : this.fieldLabel
29026 cls : 'column col-md-12',
29031 if(this.labelAlign == 'left'){
29036 html : this.fieldLabel
29045 if(this.labelWidth > 12){
29046 content[0].style = "width: " + this.labelWidth + 'px';
29049 if(this.labelWidth < 13 && this.labelmd == 0){
29050 this.labelmd = this.labelWidth;
29053 if(this.labellg > 0){
29054 content[0].cls += ' col-lg-' + this.labellg;
29055 content[1].cls += ' col-lg-' + (12 - this.labellg);
29058 if(this.labelmd > 0){
29059 content[0].cls += ' col-md-' + this.labelmd;
29060 content[1].cls += ' col-md-' + (12 - this.labelmd);
29063 if(this.labelsm > 0){
29064 content[0].cls += ' col-sm-' + this.labelsm;
29065 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29068 if(this.labelxs > 0){
29069 content[0].cls += ' col-xs-' + this.labelxs;
29070 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29078 cls : 'row clearfix',
29086 initEvents : function()
29088 this.managerEl = this.el.select('.roo-document-manager', true).first();
29089 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29091 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29092 this.selectorEl.hide();
29095 this.selectorEl.attr('multiple', 'multiple');
29098 this.selectorEl.on('change', this.onFileSelected, this);
29100 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29101 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29103 this.uploader.on('click', this.onUploaderClick, this);
29105 this.renderProgressDialog();
29109 window.addEventListener("resize", function() { _this.refresh(); } );
29111 this.fireEvent('initial', this);
29114 renderProgressDialog : function()
29118 this.progressDialog = new Roo.bootstrap.Modal({
29119 cls : 'roo-document-manager-progress-dialog',
29120 allow_close : false,
29130 btnclick : function() {
29131 _this.uploadCancel();
29137 this.progressDialog.render(Roo.get(document.body));
29139 this.progress = new Roo.bootstrap.Progress({
29140 cls : 'roo-document-manager-progress',
29145 this.progress.render(this.progressDialog.getChildContainer());
29147 this.progressBar = new Roo.bootstrap.ProgressBar({
29148 cls : 'roo-document-manager-progress-bar',
29151 aria_valuemax : 12,
29155 this.progressBar.render(this.progress.getChildContainer());
29158 onUploaderClick : function(e)
29160 e.preventDefault();
29162 if(this.fireEvent('beforeselectfile', this) != false){
29163 this.selectorEl.dom.click();
29168 onFileSelected : function(e)
29170 e.preventDefault();
29172 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29176 Roo.each(this.selectorEl.dom.files, function(file){
29177 if(this.fireEvent('inspect', this, file) != false){
29178 this.files.push(file);
29188 this.selectorEl.dom.value = '';
29190 if(!this.files || !this.files.length){
29194 if(this.boxes > 0 && this.files.length > this.boxes){
29195 this.files = this.files.slice(0, this.boxes);
29198 this.uploader.show();
29200 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29201 this.uploader.hide();
29210 Roo.each(this.files, function(file){
29212 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29213 var f = this.renderPreview(file);
29218 if(file.type.indexOf('image') != -1){
29219 this.delegates.push(
29221 _this.process(file);
29222 }).createDelegate(this)
29230 _this.process(file);
29231 }).createDelegate(this)
29236 this.files = files;
29238 this.delegates = this.delegates.concat(docs);
29240 if(!this.delegates.length){
29245 this.progressBar.aria_valuemax = this.delegates.length;
29252 arrange : function()
29254 if(!this.delegates.length){
29255 this.progressDialog.hide();
29260 var delegate = this.delegates.shift();
29262 this.progressDialog.show();
29264 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29266 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29271 refresh : function()
29273 this.uploader.show();
29275 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29276 this.uploader.hide();
29279 Roo.isTouch ? this.closable(false) : this.closable(true);
29281 this.fireEvent('refresh', this);
29284 onRemove : function(e, el, o)
29286 e.preventDefault();
29288 this.fireEvent('remove', this, o);
29292 remove : function(o)
29296 Roo.each(this.files, function(file){
29297 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29306 this.files = files;
29313 Roo.each(this.files, function(file){
29318 file.target.remove();
29327 onClick : function(e, el, o)
29329 e.preventDefault();
29331 this.fireEvent('click', this, o);
29335 closable : function(closable)
29337 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29339 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29351 xhrOnLoad : function(xhr)
29353 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29357 if (xhr.readyState !== 4) {
29359 this.fireEvent('exception', this, xhr);
29363 var response = Roo.decode(xhr.responseText);
29365 if(!response.success){
29367 this.fireEvent('exception', this, xhr);
29371 var file = this.renderPreview(response.data);
29373 this.files.push(file);
29377 this.fireEvent('afterupload', this, xhr);
29381 xhrOnError : function(xhr)
29383 Roo.log('xhr on error');
29385 var response = Roo.decode(xhr.responseText);
29392 process : function(file)
29394 if(this.fireEvent('process', this, file) !== false){
29395 if(this.editable && file.type.indexOf('image') != -1){
29396 this.fireEvent('edit', this, file);
29400 this.uploadStart(file, false);
29407 uploadStart : function(file, crop)
29409 this.xhr = new XMLHttpRequest();
29411 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29416 file.xhr = this.xhr;
29418 this.managerEl.createChild({
29420 cls : 'roo-document-manager-loading',
29424 tooltip : file.name,
29425 cls : 'roo-document-manager-thumb',
29426 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29432 this.xhr.open(this.method, this.url, true);
29435 "Accept": "application/json",
29436 "Cache-Control": "no-cache",
29437 "X-Requested-With": "XMLHttpRequest"
29440 for (var headerName in headers) {
29441 var headerValue = headers[headerName];
29443 this.xhr.setRequestHeader(headerName, headerValue);
29449 this.xhr.onload = function()
29451 _this.xhrOnLoad(_this.xhr);
29454 this.xhr.onerror = function()
29456 _this.xhrOnError(_this.xhr);
29459 var formData = new FormData();
29461 formData.append('returnHTML', 'NO');
29464 formData.append('crop', crop);
29467 formData.append(this.paramName, file, file.name);
29474 if(this.fireEvent('prepare', this, formData, options) != false){
29476 if(options.manually){
29480 this.xhr.send(formData);
29484 this.uploadCancel();
29487 uploadCancel : function()
29493 this.delegates = [];
29495 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29502 renderPreview : function(file)
29504 if(typeof(file.target) != 'undefined' && file.target){
29508 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29510 var previewEl = this.managerEl.createChild({
29512 cls : 'roo-document-manager-preview',
29516 tooltip : file[this.toolTipName],
29517 cls : 'roo-document-manager-thumb',
29518 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29523 html : '<i class="fa fa-times-circle"></i>'
29528 var close = previewEl.select('button.close', true).first();
29530 close.on('click', this.onRemove, this, file);
29532 file.target = previewEl;
29534 var image = previewEl.select('img', true).first();
29538 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29540 image.on('click', this.onClick, this, file);
29542 this.fireEvent('previewrendered', this, file);
29548 onPreviewLoad : function(file, image)
29550 if(typeof(file.target) == 'undefined' || !file.target){
29554 var width = image.dom.naturalWidth || image.dom.width;
29555 var height = image.dom.naturalHeight || image.dom.height;
29557 if(!this.previewResize) {
29561 if(width > height){
29562 file.target.addClass('wide');
29566 file.target.addClass('tall');
29571 uploadFromSource : function(file, crop)
29573 this.xhr = new XMLHttpRequest();
29575 this.managerEl.createChild({
29577 cls : 'roo-document-manager-loading',
29581 tooltip : file.name,
29582 cls : 'roo-document-manager-thumb',
29583 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29589 this.xhr.open(this.method, this.url, true);
29592 "Accept": "application/json",
29593 "Cache-Control": "no-cache",
29594 "X-Requested-With": "XMLHttpRequest"
29597 for (var headerName in headers) {
29598 var headerValue = headers[headerName];
29600 this.xhr.setRequestHeader(headerName, headerValue);
29606 this.xhr.onload = function()
29608 _this.xhrOnLoad(_this.xhr);
29611 this.xhr.onerror = function()
29613 _this.xhrOnError(_this.xhr);
29616 var formData = new FormData();
29618 formData.append('returnHTML', 'NO');
29620 formData.append('crop', crop);
29622 if(typeof(file.filename) != 'undefined'){
29623 formData.append('filename', file.filename);
29626 if(typeof(file.mimetype) != 'undefined'){
29627 formData.append('mimetype', file.mimetype);
29632 if(this.fireEvent('prepare', this, formData) != false){
29633 this.xhr.send(formData);
29643 * @class Roo.bootstrap.DocumentViewer
29644 * @extends Roo.bootstrap.Component
29645 * Bootstrap DocumentViewer class
29646 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29647 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29650 * Create a new DocumentViewer
29651 * @param {Object} config The config object
29654 Roo.bootstrap.DocumentViewer = function(config){
29655 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29660 * Fire after initEvent
29661 * @param {Roo.bootstrap.DocumentViewer} this
29667 * @param {Roo.bootstrap.DocumentViewer} this
29672 * Fire after download button
29673 * @param {Roo.bootstrap.DocumentViewer} this
29678 * Fire after trash button
29679 * @param {Roo.bootstrap.DocumentViewer} this
29686 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29688 showDownload : true,
29692 getAutoCreate : function()
29696 cls : 'roo-document-viewer',
29700 cls : 'roo-document-viewer-body',
29704 cls : 'roo-document-viewer-thumb',
29708 cls : 'roo-document-viewer-image'
29716 cls : 'roo-document-viewer-footer',
29719 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29723 cls : 'btn-group roo-document-viewer-download',
29727 cls : 'btn btn-default',
29728 html : '<i class="fa fa-download"></i>'
29734 cls : 'btn-group roo-document-viewer-trash',
29738 cls : 'btn btn-default',
29739 html : '<i class="fa fa-trash"></i>'
29752 initEvents : function()
29754 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29755 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29757 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29758 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29760 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29761 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29763 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29764 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29766 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29767 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29769 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29770 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29772 this.bodyEl.on('click', this.onClick, this);
29773 this.downloadBtn.on('click', this.onDownload, this);
29774 this.trashBtn.on('click', this.onTrash, this);
29776 this.downloadBtn.hide();
29777 this.trashBtn.hide();
29779 if(this.showDownload){
29780 this.downloadBtn.show();
29783 if(this.showTrash){
29784 this.trashBtn.show();
29787 if(!this.showDownload && !this.showTrash) {
29788 this.footerEl.hide();
29793 initial : function()
29795 this.fireEvent('initial', this);
29799 onClick : function(e)
29801 e.preventDefault();
29803 this.fireEvent('click', this);
29806 onDownload : function(e)
29808 e.preventDefault();
29810 this.fireEvent('download', this);
29813 onTrash : function(e)
29815 e.preventDefault();
29817 this.fireEvent('trash', this);
29829 * @class Roo.bootstrap.NavProgressBar
29830 * @extends Roo.bootstrap.Component
29831 * Bootstrap NavProgressBar class
29834 * Create a new nav progress bar
29835 * @param {Object} config The config object
29838 Roo.bootstrap.NavProgressBar = function(config){
29839 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29841 this.bullets = this.bullets || [];
29843 // Roo.bootstrap.NavProgressBar.register(this);
29847 * Fires when the active item changes
29848 * @param {Roo.bootstrap.NavProgressBar} this
29849 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29850 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29857 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29862 getAutoCreate : function()
29864 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29868 cls : 'roo-navigation-bar-group',
29872 cls : 'roo-navigation-top-bar'
29876 cls : 'roo-navigation-bullets-bar',
29880 cls : 'roo-navigation-bar'
29887 cls : 'roo-navigation-bottom-bar'
29897 initEvents: function()
29902 onRender : function(ct, position)
29904 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29906 if(this.bullets.length){
29907 Roo.each(this.bullets, function(b){
29916 addItem : function(cfg)
29918 var item = new Roo.bootstrap.NavProgressItem(cfg);
29920 item.parentId = this.id;
29921 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29924 var top = new Roo.bootstrap.Element({
29926 cls : 'roo-navigation-bar-text'
29929 var bottom = new Roo.bootstrap.Element({
29931 cls : 'roo-navigation-bar-text'
29934 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29935 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29937 var topText = new Roo.bootstrap.Element({
29939 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29942 var bottomText = new Roo.bootstrap.Element({
29944 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29947 topText.onRender(top.el, null);
29948 bottomText.onRender(bottom.el, null);
29951 item.bottomEl = bottom;
29954 this.barItems.push(item);
29959 getActive : function()
29961 var active = false;
29963 Roo.each(this.barItems, function(v){
29965 if (!v.isActive()) {
29977 setActiveItem : function(item)
29981 Roo.each(this.barItems, function(v){
29982 if (v.rid == item.rid) {
29986 if (v.isActive()) {
29987 v.setActive(false);
29992 item.setActive(true);
29994 this.fireEvent('changed', this, item, prev);
29997 getBarItem: function(rid)
30001 Roo.each(this.barItems, function(e) {
30002 if (e.rid != rid) {
30013 indexOfItem : function(item)
30017 Roo.each(this.barItems, function(v, i){
30019 if (v.rid != item.rid) {
30030 setActiveNext : function()
30032 var i = this.indexOfItem(this.getActive());
30034 if (i > this.barItems.length) {
30038 this.setActiveItem(this.barItems[i+1]);
30041 setActivePrev : function()
30043 var i = this.indexOfItem(this.getActive());
30049 this.setActiveItem(this.barItems[i-1]);
30052 format : function()
30054 if(!this.barItems.length){
30058 var width = 100 / this.barItems.length;
30060 Roo.each(this.barItems, function(i){
30061 i.el.setStyle('width', width + '%');
30062 i.topEl.el.setStyle('width', width + '%');
30063 i.bottomEl.el.setStyle('width', width + '%');
30072 * Nav Progress Item
30077 * @class Roo.bootstrap.NavProgressItem
30078 * @extends Roo.bootstrap.Component
30079 * Bootstrap NavProgressItem class
30080 * @cfg {String} rid the reference id
30081 * @cfg {Boolean} active (true|false) Is item active default false
30082 * @cfg {Boolean} disabled (true|false) Is item active default false
30083 * @cfg {String} html
30084 * @cfg {String} position (top|bottom) text position default bottom
30085 * @cfg {String} icon show icon instead of number
30088 * Create a new NavProgressItem
30089 * @param {Object} config The config object
30091 Roo.bootstrap.NavProgressItem = function(config){
30092 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30097 * The raw click event for the entire grid.
30098 * @param {Roo.bootstrap.NavProgressItem} this
30099 * @param {Roo.EventObject} e
30106 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30112 position : 'bottom',
30115 getAutoCreate : function()
30117 var iconCls = 'roo-navigation-bar-item-icon';
30119 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30123 cls: 'roo-navigation-bar-item',
30133 cfg.cls += ' active';
30136 cfg.cls += ' disabled';
30142 disable : function()
30144 this.setDisabled(true);
30147 enable : function()
30149 this.setDisabled(false);
30152 initEvents: function()
30154 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30156 this.iconEl.on('click', this.onClick, this);
30159 onClick : function(e)
30161 e.preventDefault();
30167 if(this.fireEvent('click', this, e) === false){
30171 this.parent().setActiveItem(this);
30174 isActive: function ()
30176 return this.active;
30179 setActive : function(state)
30181 if(this.active == state){
30185 this.active = state;
30188 this.el.addClass('active');
30192 this.el.removeClass('active');
30197 setDisabled : function(state)
30199 if(this.disabled == state){
30203 this.disabled = state;
30206 this.el.addClass('disabled');
30210 this.el.removeClass('disabled');
30213 tooltipEl : function()
30215 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30228 * @class Roo.bootstrap.FieldLabel
30229 * @extends Roo.bootstrap.Component
30230 * Bootstrap FieldLabel class
30231 * @cfg {String} html contents of the element
30232 * @cfg {String} tag tag of the element default label
30233 * @cfg {String} cls class of the element
30234 * @cfg {String} target label target
30235 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30236 * @cfg {String} invalidClass default "text-warning"
30237 * @cfg {String} validClass default "text-success"
30238 * @cfg {String} iconTooltip default "This field is required"
30239 * @cfg {String} indicatorpos (left|right) default left
30242 * Create a new FieldLabel
30243 * @param {Object} config The config object
30246 Roo.bootstrap.FieldLabel = function(config){
30247 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30252 * Fires after the field has been marked as invalid.
30253 * @param {Roo.form.FieldLabel} this
30254 * @param {String} msg The validation message
30259 * Fires after the field has been validated with no errors.
30260 * @param {Roo.form.FieldLabel} this
30266 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30273 invalidClass : 'has-warning',
30274 validClass : 'has-success',
30275 iconTooltip : 'This field is required',
30276 indicatorpos : 'left',
30278 getAutoCreate : function(){
30281 if (!this.allowBlank) {
30287 cls : 'roo-bootstrap-field-label ' + this.cls,
30292 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30293 tooltip : this.iconTooltip
30302 if(this.indicatorpos == 'right'){
30305 cls : 'roo-bootstrap-field-label ' + this.cls,
30314 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30315 tooltip : this.iconTooltip
30324 initEvents: function()
30326 Roo.bootstrap.Element.superclass.initEvents.call(this);
30328 this.indicator = this.indicatorEl();
30330 if(this.indicator){
30331 this.indicator.removeClass('visible');
30332 this.indicator.addClass('invisible');
30335 Roo.bootstrap.FieldLabel.register(this);
30338 indicatorEl : function()
30340 var indicator = this.el.select('i.roo-required-indicator',true).first();
30351 * Mark this field as valid
30353 markValid : function()
30355 if(this.indicator){
30356 this.indicator.removeClass('visible');
30357 this.indicator.addClass('invisible');
30360 this.el.removeClass(this.invalidClass);
30362 this.el.addClass(this.validClass);
30364 this.fireEvent('valid', this);
30368 * Mark this field as invalid
30369 * @param {String} msg The validation message
30371 markInvalid : function(msg)
30373 if(this.indicator){
30374 this.indicator.removeClass('invisible');
30375 this.indicator.addClass('visible');
30378 this.el.removeClass(this.validClass);
30380 this.el.addClass(this.invalidClass);
30382 this.fireEvent('invalid', this, msg);
30388 Roo.apply(Roo.bootstrap.FieldLabel, {
30393 * register a FieldLabel Group
30394 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30396 register : function(label)
30398 if(this.groups.hasOwnProperty(label.target)){
30402 this.groups[label.target] = label;
30406 * fetch a FieldLabel Group based on the target
30407 * @param {string} target
30408 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30410 get: function(target) {
30411 if (typeof(this.groups[target]) == 'undefined') {
30415 return this.groups[target] ;
30424 * page DateSplitField.
30430 * @class Roo.bootstrap.DateSplitField
30431 * @extends Roo.bootstrap.Component
30432 * Bootstrap DateSplitField class
30433 * @cfg {string} fieldLabel - the label associated
30434 * @cfg {Number} labelWidth set the width of label (0-12)
30435 * @cfg {String} labelAlign (top|left)
30436 * @cfg {Boolean} dayAllowBlank (true|false) default false
30437 * @cfg {Boolean} monthAllowBlank (true|false) default false
30438 * @cfg {Boolean} yearAllowBlank (true|false) default false
30439 * @cfg {string} dayPlaceholder
30440 * @cfg {string} monthPlaceholder
30441 * @cfg {string} yearPlaceholder
30442 * @cfg {string} dayFormat default 'd'
30443 * @cfg {string} monthFormat default 'm'
30444 * @cfg {string} yearFormat default 'Y'
30445 * @cfg {Number} labellg set the width of label (1-12)
30446 * @cfg {Number} labelmd set the width of label (1-12)
30447 * @cfg {Number} labelsm set the width of label (1-12)
30448 * @cfg {Number} labelxs set the width of label (1-12)
30452 * Create a new DateSplitField
30453 * @param {Object} config The config object
30456 Roo.bootstrap.DateSplitField = function(config){
30457 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30463 * getting the data of years
30464 * @param {Roo.bootstrap.DateSplitField} this
30465 * @param {Object} years
30470 * getting the data of days
30471 * @param {Roo.bootstrap.DateSplitField} this
30472 * @param {Object} days
30477 * Fires after the field has been marked as invalid.
30478 * @param {Roo.form.Field} this
30479 * @param {String} msg The validation message
30484 * Fires after the field has been validated with no errors.
30485 * @param {Roo.form.Field} this
30491 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30494 labelAlign : 'top',
30496 dayAllowBlank : false,
30497 monthAllowBlank : false,
30498 yearAllowBlank : false,
30499 dayPlaceholder : '',
30500 monthPlaceholder : '',
30501 yearPlaceholder : '',
30505 isFormField : true,
30511 getAutoCreate : function()
30515 cls : 'row roo-date-split-field-group',
30520 cls : 'form-hidden-field roo-date-split-field-group-value',
30526 var labelCls = 'col-md-12';
30527 var contentCls = 'col-md-4';
30529 if(this.fieldLabel){
30533 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30537 html : this.fieldLabel
30542 if(this.labelAlign == 'left'){
30544 if(this.labelWidth > 12){
30545 label.style = "width: " + this.labelWidth + 'px';
30548 if(this.labelWidth < 13 && this.labelmd == 0){
30549 this.labelmd = this.labelWidth;
30552 if(this.labellg > 0){
30553 labelCls = ' col-lg-' + this.labellg;
30554 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30557 if(this.labelmd > 0){
30558 labelCls = ' col-md-' + this.labelmd;
30559 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30562 if(this.labelsm > 0){
30563 labelCls = ' col-sm-' + this.labelsm;
30564 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30567 if(this.labelxs > 0){
30568 labelCls = ' col-xs-' + this.labelxs;
30569 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30573 label.cls += ' ' + labelCls;
30575 cfg.cn.push(label);
30578 Roo.each(['day', 'month', 'year'], function(t){
30581 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30588 inputEl: function ()
30590 return this.el.select('.roo-date-split-field-group-value', true).first();
30593 onRender : function(ct, position)
30597 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30599 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30601 this.dayField = new Roo.bootstrap.ComboBox({
30602 allowBlank : this.dayAllowBlank,
30603 alwaysQuery : true,
30604 displayField : 'value',
30607 forceSelection : true,
30609 placeholder : this.dayPlaceholder,
30610 selectOnFocus : true,
30611 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30612 triggerAction : 'all',
30614 valueField : 'value',
30615 store : new Roo.data.SimpleStore({
30616 data : (function() {
30618 _this.fireEvent('days', _this, days);
30621 fields : [ 'value' ]
30624 select : function (_self, record, index)
30626 _this.setValue(_this.getValue());
30631 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30633 this.monthField = new Roo.bootstrap.MonthField({
30634 after : '<i class=\"fa fa-calendar\"></i>',
30635 allowBlank : this.monthAllowBlank,
30636 placeholder : this.monthPlaceholder,
30639 render : function (_self)
30641 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30642 e.preventDefault();
30646 select : function (_self, oldvalue, newvalue)
30648 _this.setValue(_this.getValue());
30653 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30655 this.yearField = new Roo.bootstrap.ComboBox({
30656 allowBlank : this.yearAllowBlank,
30657 alwaysQuery : true,
30658 displayField : 'value',
30661 forceSelection : true,
30663 placeholder : this.yearPlaceholder,
30664 selectOnFocus : true,
30665 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30666 triggerAction : 'all',
30668 valueField : 'value',
30669 store : new Roo.data.SimpleStore({
30670 data : (function() {
30672 _this.fireEvent('years', _this, years);
30675 fields : [ 'value' ]
30678 select : function (_self, record, index)
30680 _this.setValue(_this.getValue());
30685 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30688 setValue : function(v, format)
30690 this.inputEl.dom.value = v;
30692 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30694 var d = Date.parseDate(v, f);
30701 this.setDay(d.format(this.dayFormat));
30702 this.setMonth(d.format(this.monthFormat));
30703 this.setYear(d.format(this.yearFormat));
30710 setDay : function(v)
30712 this.dayField.setValue(v);
30713 this.inputEl.dom.value = this.getValue();
30718 setMonth : function(v)
30720 this.monthField.setValue(v, true);
30721 this.inputEl.dom.value = this.getValue();
30726 setYear : function(v)
30728 this.yearField.setValue(v);
30729 this.inputEl.dom.value = this.getValue();
30734 getDay : function()
30736 return this.dayField.getValue();
30739 getMonth : function()
30741 return this.monthField.getValue();
30744 getYear : function()
30746 return this.yearField.getValue();
30749 getValue : function()
30751 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30753 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30763 this.inputEl.dom.value = '';
30768 validate : function()
30770 var d = this.dayField.validate();
30771 var m = this.monthField.validate();
30772 var y = this.yearField.validate();
30777 (!this.dayAllowBlank && !d) ||
30778 (!this.monthAllowBlank && !m) ||
30779 (!this.yearAllowBlank && !y)
30784 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30793 this.markInvalid();
30798 markValid : function()
30801 var label = this.el.select('label', true).first();
30802 var icon = this.el.select('i.fa-star', true).first();
30808 this.fireEvent('valid', this);
30812 * Mark this field as invalid
30813 * @param {String} msg The validation message
30815 markInvalid : function(msg)
30818 var label = this.el.select('label', true).first();
30819 var icon = this.el.select('i.fa-star', true).first();
30821 if(label && !icon){
30822 this.el.select('.roo-date-split-field-label', true).createChild({
30824 cls : 'text-danger fa fa-lg fa-star',
30825 tooltip : 'This field is required',
30826 style : 'margin-right:5px;'
30830 this.fireEvent('invalid', this, msg);
30833 clearInvalid : function()
30835 var label = this.el.select('label', true).first();
30836 var icon = this.el.select('i.fa-star', true).first();
30842 this.fireEvent('valid', this);
30845 getName: function()
30855 * http://masonry.desandro.com
30857 * The idea is to render all the bricks based on vertical width...
30859 * The original code extends 'outlayer' - we might need to use that....
30865 * @class Roo.bootstrap.LayoutMasonry
30866 * @extends Roo.bootstrap.Component
30867 * Bootstrap Layout Masonry class
30870 * Create a new Element
30871 * @param {Object} config The config object
30874 Roo.bootstrap.LayoutMasonry = function(config){
30876 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30880 Roo.bootstrap.LayoutMasonry.register(this);
30886 * Fire after layout the items
30887 * @param {Roo.bootstrap.LayoutMasonry} this
30888 * @param {Roo.EventObject} e
30895 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30898 * @cfg {Boolean} isLayoutInstant = no animation?
30900 isLayoutInstant : false, // needed?
30903 * @cfg {Number} boxWidth width of the columns
30908 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30913 * @cfg {Number} padWidth padding below box..
30918 * @cfg {Number} gutter gutter width..
30923 * @cfg {Number} maxCols maximum number of columns
30929 * @cfg {Boolean} isAutoInitial defalut true
30931 isAutoInitial : true,
30936 * @cfg {Boolean} isHorizontal defalut false
30938 isHorizontal : false,
30940 currentSize : null,
30946 bricks: null, //CompositeElement
30950 _isLayoutInited : false,
30952 // isAlternative : false, // only use for vertical layout...
30955 * @cfg {Number} alternativePadWidth padding below box..
30957 alternativePadWidth : 50,
30959 selectedBrick : [],
30961 getAutoCreate : function(){
30963 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30967 cls: 'blog-masonary-wrapper ' + this.cls,
30969 cls : 'mas-boxes masonary'
30976 getChildContainer: function( )
30978 if (this.boxesEl) {
30979 return this.boxesEl;
30982 this.boxesEl = this.el.select('.mas-boxes').first();
30984 return this.boxesEl;
30988 initEvents : function()
30992 if(this.isAutoInitial){
30993 Roo.log('hook children rendered');
30994 this.on('childrenrendered', function() {
30995 Roo.log('children rendered');
31001 initial : function()
31003 this.selectedBrick = [];
31005 this.currentSize = this.el.getBox(true);
31007 Roo.EventManager.onWindowResize(this.resize, this);
31009 if(!this.isAutoInitial){
31017 //this.layout.defer(500,this);
31021 resize : function()
31023 var cs = this.el.getBox(true);
31026 this.currentSize.width == cs.width &&
31027 this.currentSize.x == cs.x &&
31028 this.currentSize.height == cs.height &&
31029 this.currentSize.y == cs.y
31031 Roo.log("no change in with or X or Y");
31035 this.currentSize = cs;
31041 layout : function()
31043 this._resetLayout();
31045 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31047 this.layoutItems( isInstant );
31049 this._isLayoutInited = true;
31051 this.fireEvent('layout', this);
31055 _resetLayout : function()
31057 if(this.isHorizontal){
31058 this.horizontalMeasureColumns();
31062 this.verticalMeasureColumns();
31066 verticalMeasureColumns : function()
31068 this.getContainerWidth();
31070 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31071 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31075 var boxWidth = this.boxWidth + this.padWidth;
31077 if(this.containerWidth < this.boxWidth){
31078 boxWidth = this.containerWidth
31081 var containerWidth = this.containerWidth;
31083 var cols = Math.floor(containerWidth / boxWidth);
31085 this.cols = Math.max( cols, 1 );
31087 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31089 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31091 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31093 this.colWidth = boxWidth + avail - this.padWidth;
31095 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31096 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31099 horizontalMeasureColumns : function()
31101 this.getContainerWidth();
31103 var boxWidth = this.boxWidth;
31105 if(this.containerWidth < boxWidth){
31106 boxWidth = this.containerWidth;
31109 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31111 this.el.setHeight(boxWidth);
31115 getContainerWidth : function()
31117 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31120 layoutItems : function( isInstant )
31122 Roo.log(this.bricks);
31124 var items = Roo.apply([], this.bricks);
31126 if(this.isHorizontal){
31127 this._horizontalLayoutItems( items , isInstant );
31131 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31132 // this._verticalAlternativeLayoutItems( items , isInstant );
31136 this._verticalLayoutItems( items , isInstant );
31140 _verticalLayoutItems : function ( items , isInstant)
31142 if ( !items || !items.length ) {
31147 ['xs', 'xs', 'xs', 'tall'],
31148 ['xs', 'xs', 'tall'],
31149 ['xs', 'xs', 'sm'],
31150 ['xs', 'xs', 'xs'],
31156 ['sm', 'xs', 'xs'],
31160 ['tall', 'xs', 'xs', 'xs'],
31161 ['tall', 'xs', 'xs'],
31173 Roo.each(items, function(item, k){
31175 switch (item.size) {
31176 // these layouts take up a full box,
31187 boxes.push([item]);
31210 var filterPattern = function(box, length)
31218 var pattern = box.slice(0, length);
31222 Roo.each(pattern, function(i){
31223 format.push(i.size);
31226 Roo.each(standard, function(s){
31228 if(String(s) != String(format)){
31237 if(!match && length == 1){
31242 filterPattern(box, length - 1);
31246 queue.push(pattern);
31248 box = box.slice(length, box.length);
31250 filterPattern(box, 4);
31256 Roo.each(boxes, function(box, k){
31262 if(box.length == 1){
31267 filterPattern(box, 4);
31271 this._processVerticalLayoutQueue( queue, isInstant );
31275 // _verticalAlternativeLayoutItems : function( items , isInstant )
31277 // if ( !items || !items.length ) {
31281 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31285 _horizontalLayoutItems : function ( items , isInstant)
31287 if ( !items || !items.length || items.length < 3) {
31293 var eItems = items.slice(0, 3);
31295 items = items.slice(3, items.length);
31298 ['xs', 'xs', 'xs', 'wide'],
31299 ['xs', 'xs', 'wide'],
31300 ['xs', 'xs', 'sm'],
31301 ['xs', 'xs', 'xs'],
31307 ['sm', 'xs', 'xs'],
31311 ['wide', 'xs', 'xs', 'xs'],
31312 ['wide', 'xs', 'xs'],
31325 Roo.each(items, function(item, k){
31327 switch (item.size) {
31338 boxes.push([item]);
31362 var filterPattern = function(box, length)
31370 var pattern = box.slice(0, length);
31374 Roo.each(pattern, function(i){
31375 format.push(i.size);
31378 Roo.each(standard, function(s){
31380 if(String(s) != String(format)){
31389 if(!match && length == 1){
31394 filterPattern(box, length - 1);
31398 queue.push(pattern);
31400 box = box.slice(length, box.length);
31402 filterPattern(box, 4);
31408 Roo.each(boxes, function(box, k){
31414 if(box.length == 1){
31419 filterPattern(box, 4);
31426 var pos = this.el.getBox(true);
31430 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31432 var hit_end = false;
31434 Roo.each(queue, function(box){
31438 Roo.each(box, function(b){
31440 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31450 Roo.each(box, function(b){
31452 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31455 mx = Math.max(mx, b.x);
31459 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31463 Roo.each(box, function(b){
31465 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31479 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31482 /** Sets position of item in DOM
31483 * @param {Element} item
31484 * @param {Number} x - horizontal position
31485 * @param {Number} y - vertical position
31486 * @param {Boolean} isInstant - disables transitions
31488 _processVerticalLayoutQueue : function( queue, isInstant )
31490 var pos = this.el.getBox(true);
31495 for (var i = 0; i < this.cols; i++){
31499 Roo.each(queue, function(box, k){
31501 var col = k % this.cols;
31503 Roo.each(box, function(b,kk){
31505 b.el.position('absolute');
31507 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31508 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31510 if(b.size == 'md-left' || b.size == 'md-right'){
31511 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31512 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31515 b.el.setWidth(width);
31516 b.el.setHeight(height);
31518 b.el.select('iframe',true).setSize(width,height);
31522 for (var i = 0; i < this.cols; i++){
31524 if(maxY[i] < maxY[col]){
31529 col = Math.min(col, i);
31533 x = pos.x + col * (this.colWidth + this.padWidth);
31537 var positions = [];
31539 switch (box.length){
31541 positions = this.getVerticalOneBoxColPositions(x, y, box);
31544 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31547 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31550 positions = this.getVerticalFourBoxColPositions(x, y, box);
31556 Roo.each(box, function(b,kk){
31558 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31560 var sz = b.el.getSize();
31562 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31570 for (var i = 0; i < this.cols; i++){
31571 mY = Math.max(mY, maxY[i]);
31574 this.el.setHeight(mY - pos.y);
31578 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31580 // var pos = this.el.getBox(true);
31583 // var maxX = pos.right;
31585 // var maxHeight = 0;
31587 // Roo.each(items, function(item, k){
31591 // item.el.position('absolute');
31593 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31595 // item.el.setWidth(width);
31597 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31599 // item.el.setHeight(height);
31602 // item.el.setXY([x, y], isInstant ? false : true);
31604 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31607 // y = y + height + this.alternativePadWidth;
31609 // maxHeight = maxHeight + height + this.alternativePadWidth;
31613 // this.el.setHeight(maxHeight);
31617 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31619 var pos = this.el.getBox(true);
31624 var maxX = pos.right;
31626 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31628 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31630 Roo.each(queue, function(box, k){
31632 Roo.each(box, function(b, kk){
31634 b.el.position('absolute');
31636 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31637 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31639 if(b.size == 'md-left' || b.size == 'md-right'){
31640 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31641 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31644 b.el.setWidth(width);
31645 b.el.setHeight(height);
31653 var positions = [];
31655 switch (box.length){
31657 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31660 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31663 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31666 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31672 Roo.each(box, function(b,kk){
31674 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31676 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31684 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31686 Roo.each(eItems, function(b,k){
31688 b.size = (k == 0) ? 'sm' : 'xs';
31689 b.x = (k == 0) ? 2 : 1;
31690 b.y = (k == 0) ? 2 : 1;
31692 b.el.position('absolute');
31694 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31696 b.el.setWidth(width);
31698 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31700 b.el.setHeight(height);
31704 var positions = [];
31707 x : maxX - this.unitWidth * 2 - this.gutter,
31712 x : maxX - this.unitWidth,
31713 y : minY + (this.unitWidth + this.gutter) * 2
31717 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31721 Roo.each(eItems, function(b,k){
31723 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31729 getVerticalOneBoxColPositions : function(x, y, box)
31733 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31735 if(box[0].size == 'md-left'){
31739 if(box[0].size == 'md-right'){
31744 x : x + (this.unitWidth + this.gutter) * rand,
31751 getVerticalTwoBoxColPositions : function(x, y, box)
31755 if(box[0].size == 'xs'){
31759 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31763 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31777 x : x + (this.unitWidth + this.gutter) * 2,
31778 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31785 getVerticalThreeBoxColPositions : function(x, y, box)
31789 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31797 x : x + (this.unitWidth + this.gutter) * 1,
31802 x : x + (this.unitWidth + this.gutter) * 2,
31810 if(box[0].size == 'xs' && box[1].size == 'xs'){
31819 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31823 x : x + (this.unitWidth + this.gutter) * 1,
31837 x : x + (this.unitWidth + this.gutter) * 2,
31842 x : x + (this.unitWidth + this.gutter) * 2,
31843 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31850 getVerticalFourBoxColPositions : function(x, y, box)
31854 if(box[0].size == 'xs'){
31863 y : y + (this.unitHeight + this.gutter) * 1
31868 y : y + (this.unitHeight + this.gutter) * 2
31872 x : x + (this.unitWidth + this.gutter) * 1,
31886 x : x + (this.unitWidth + this.gutter) * 2,
31891 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31892 y : y + (this.unitHeight + this.gutter) * 1
31896 x : x + (this.unitWidth + this.gutter) * 2,
31897 y : y + (this.unitWidth + this.gutter) * 2
31904 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31908 if(box[0].size == 'md-left'){
31910 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31917 if(box[0].size == 'md-right'){
31919 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31920 y : minY + (this.unitWidth + this.gutter) * 1
31926 var rand = Math.floor(Math.random() * (4 - box[0].y));
31929 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31930 y : minY + (this.unitWidth + this.gutter) * rand
31937 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31941 if(box[0].size == 'xs'){
31944 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31949 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31950 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31958 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31963 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31964 y : minY + (this.unitWidth + this.gutter) * 2
31971 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31975 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31978 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31983 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31984 y : minY + (this.unitWidth + this.gutter) * 1
31988 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31989 y : minY + (this.unitWidth + this.gutter) * 2
31996 if(box[0].size == 'xs' && box[1].size == 'xs'){
31999 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32004 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32009 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32010 y : minY + (this.unitWidth + this.gutter) * 1
32018 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32023 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32024 y : minY + (this.unitWidth + this.gutter) * 2
32028 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32029 y : minY + (this.unitWidth + this.gutter) * 2
32036 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32040 if(box[0].size == 'xs'){
32043 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32048 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32053 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),
32058 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32059 y : minY + (this.unitWidth + this.gutter) * 1
32067 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32072 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32073 y : minY + (this.unitWidth + this.gutter) * 2
32077 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32078 y : minY + (this.unitWidth + this.gutter) * 2
32082 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),
32083 y : minY + (this.unitWidth + this.gutter) * 2
32091 * remove a Masonry Brick
32092 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32094 removeBrick : function(brick_id)
32100 for (var i = 0; i<this.bricks.length; i++) {
32101 if (this.bricks[i].id == brick_id) {
32102 this.bricks.splice(i,1);
32103 this.el.dom.removeChild(Roo.get(brick_id).dom);
32110 * adds a Masonry Brick
32111 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32113 addBrick : function(cfg)
32115 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32116 //this.register(cn);
32117 cn.parentId = this.id;
32118 cn.render(this.el);
32123 * register a Masonry Brick
32124 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32127 register : function(brick)
32129 this.bricks.push(brick);
32130 brick.masonryId = this.id;
32134 * clear all the Masonry Brick
32136 clearAll : function()
32139 //this.getChildContainer().dom.innerHTML = "";
32140 this.el.dom.innerHTML = '';
32143 getSelected : function()
32145 if (!this.selectedBrick) {
32149 return this.selectedBrick;
32153 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32157 * register a Masonry Layout
32158 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32161 register : function(layout)
32163 this.groups[layout.id] = layout;
32166 * fetch a Masonry Layout based on the masonry layout ID
32167 * @param {string} the masonry layout to add
32168 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32171 get: function(layout_id) {
32172 if (typeof(this.groups[layout_id]) == 'undefined') {
32175 return this.groups[layout_id] ;
32187 * http://masonry.desandro.com
32189 * The idea is to render all the bricks based on vertical width...
32191 * The original code extends 'outlayer' - we might need to use that....
32197 * @class Roo.bootstrap.LayoutMasonryAuto
32198 * @extends Roo.bootstrap.Component
32199 * Bootstrap Layout Masonry class
32202 * Create a new Element
32203 * @param {Object} config The config object
32206 Roo.bootstrap.LayoutMasonryAuto = function(config){
32207 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32210 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32213 * @cfg {Boolean} isFitWidth - resize the width..
32215 isFitWidth : false, // options..
32217 * @cfg {Boolean} isOriginLeft = left align?
32219 isOriginLeft : true,
32221 * @cfg {Boolean} isOriginTop = top align?
32223 isOriginTop : false,
32225 * @cfg {Boolean} isLayoutInstant = no animation?
32227 isLayoutInstant : false, // needed?
32229 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32231 isResizingContainer : true,
32233 * @cfg {Number} columnWidth width of the columns
32239 * @cfg {Number} maxCols maximum number of columns
32244 * @cfg {Number} padHeight padding below box..
32250 * @cfg {Boolean} isAutoInitial defalut true
32253 isAutoInitial : true,
32259 initialColumnWidth : 0,
32260 currentSize : null,
32262 colYs : null, // array.
32269 bricks: null, //CompositeElement
32270 cols : 0, // array?
32271 // element : null, // wrapped now this.el
32272 _isLayoutInited : null,
32275 getAutoCreate : function(){
32279 cls: 'blog-masonary-wrapper ' + this.cls,
32281 cls : 'mas-boxes masonary'
32288 getChildContainer: function( )
32290 if (this.boxesEl) {
32291 return this.boxesEl;
32294 this.boxesEl = this.el.select('.mas-boxes').first();
32296 return this.boxesEl;
32300 initEvents : function()
32304 if(this.isAutoInitial){
32305 Roo.log('hook children rendered');
32306 this.on('childrenrendered', function() {
32307 Roo.log('children rendered');
32314 initial : function()
32316 this.reloadItems();
32318 this.currentSize = this.el.getBox(true);
32320 /// was window resize... - let's see if this works..
32321 Roo.EventManager.onWindowResize(this.resize, this);
32323 if(!this.isAutoInitial){
32328 this.layout.defer(500,this);
32331 reloadItems: function()
32333 this.bricks = this.el.select('.masonry-brick', true);
32335 this.bricks.each(function(b) {
32336 //Roo.log(b.getSize());
32337 if (!b.attr('originalwidth')) {
32338 b.attr('originalwidth', b.getSize().width);
32343 Roo.log(this.bricks.elements.length);
32346 resize : function()
32349 var cs = this.el.getBox(true);
32351 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32352 Roo.log("no change in with or X");
32355 this.currentSize = cs;
32359 layout : function()
32362 this._resetLayout();
32363 //this._manageStamps();
32365 // don't animate first layout
32366 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32367 this.layoutItems( isInstant );
32369 // flag for initalized
32370 this._isLayoutInited = true;
32373 layoutItems : function( isInstant )
32375 //var items = this._getItemsForLayout( this.items );
32376 // original code supports filtering layout items.. we just ignore it..
32378 this._layoutItems( this.bricks , isInstant );
32380 this._postLayout();
32382 _layoutItems : function ( items , isInstant)
32384 //this.fireEvent( 'layout', this, items );
32387 if ( !items || !items.elements.length ) {
32388 // no items, emit event with empty array
32393 items.each(function(item) {
32394 Roo.log("layout item");
32396 // get x/y object from method
32397 var position = this._getItemLayoutPosition( item );
32399 position.item = item;
32400 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32401 queue.push( position );
32404 this._processLayoutQueue( queue );
32406 /** Sets position of item in DOM
32407 * @param {Element} item
32408 * @param {Number} x - horizontal position
32409 * @param {Number} y - vertical position
32410 * @param {Boolean} isInstant - disables transitions
32412 _processLayoutQueue : function( queue )
32414 for ( var i=0, len = queue.length; i < len; i++ ) {
32415 var obj = queue[i];
32416 obj.item.position('absolute');
32417 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32423 * Any logic you want to do after each layout,
32424 * i.e. size the container
32426 _postLayout : function()
32428 this.resizeContainer();
32431 resizeContainer : function()
32433 if ( !this.isResizingContainer ) {
32436 var size = this._getContainerSize();
32438 this.el.setSize(size.width,size.height);
32439 this.boxesEl.setSize(size.width,size.height);
32445 _resetLayout : function()
32447 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32448 this.colWidth = this.el.getWidth();
32449 //this.gutter = this.el.getWidth();
32451 this.measureColumns();
32457 this.colYs.push( 0 );
32463 measureColumns : function()
32465 this.getContainerWidth();
32466 // if columnWidth is 0, default to outerWidth of first item
32467 if ( !this.columnWidth ) {
32468 var firstItem = this.bricks.first();
32469 Roo.log(firstItem);
32470 this.columnWidth = this.containerWidth;
32471 if (firstItem && firstItem.attr('originalwidth') ) {
32472 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32474 // columnWidth fall back to item of first element
32475 Roo.log("set column width?");
32476 this.initialColumnWidth = this.columnWidth ;
32478 // if first elem has no width, default to size of container
32483 if (this.initialColumnWidth) {
32484 this.columnWidth = this.initialColumnWidth;
32489 // column width is fixed at the top - however if container width get's smaller we should
32492 // this bit calcs how man columns..
32494 var columnWidth = this.columnWidth += this.gutter;
32496 // calculate columns
32497 var containerWidth = this.containerWidth + this.gutter;
32499 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32500 // fix rounding errors, typically with gutters
32501 var excess = columnWidth - containerWidth % columnWidth;
32504 // if overshoot is less than a pixel, round up, otherwise floor it
32505 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32506 cols = Math[ mathMethod ]( cols );
32507 this.cols = Math.max( cols, 1 );
32508 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32510 // padding positioning..
32511 var totalColWidth = this.cols * this.columnWidth;
32512 var padavail = this.containerWidth - totalColWidth;
32513 // so for 2 columns - we need 3 'pads'
32515 var padNeeded = (1+this.cols) * this.padWidth;
32517 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32519 this.columnWidth += padExtra
32520 //this.padWidth = Math.floor(padavail / ( this.cols));
32522 // adjust colum width so that padding is fixed??
32524 // we have 3 columns ... total = width * 3
32525 // we have X left over... that should be used by
32527 //if (this.expandC) {
32535 getContainerWidth : function()
32537 /* // container is parent if fit width
32538 var container = this.isFitWidth ? this.element.parentNode : this.element;
32539 // check that this.size and size are there
32540 // IE8 triggers resize on body size change, so they might not be
32542 var size = getSize( container ); //FIXME
32543 this.containerWidth = size && size.innerWidth; //FIXME
32546 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32550 _getItemLayoutPosition : function( item ) // what is item?
32552 // we resize the item to our columnWidth..
32554 item.setWidth(this.columnWidth);
32555 item.autoBoxAdjust = false;
32557 var sz = item.getSize();
32559 // how many columns does this brick span
32560 var remainder = this.containerWidth % this.columnWidth;
32562 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32563 // round if off by 1 pixel, otherwise use ceil
32564 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32565 colSpan = Math.min( colSpan, this.cols );
32567 // normally this should be '1' as we dont' currently allow multi width columns..
32569 var colGroup = this._getColGroup( colSpan );
32570 // get the minimum Y value from the columns
32571 var minimumY = Math.min.apply( Math, colGroup );
32572 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32574 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32576 // position the brick
32578 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32579 y: this.currentSize.y + minimumY + this.padHeight
32583 // apply setHeight to necessary columns
32584 var setHeight = minimumY + sz.height + this.padHeight;
32585 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32587 var setSpan = this.cols + 1 - colGroup.length;
32588 for ( var i = 0; i < setSpan; i++ ) {
32589 this.colYs[ shortColIndex + i ] = setHeight ;
32596 * @param {Number} colSpan - number of columns the element spans
32597 * @returns {Array} colGroup
32599 _getColGroup : function( colSpan )
32601 if ( colSpan < 2 ) {
32602 // if brick spans only one column, use all the column Ys
32607 // how many different places could this brick fit horizontally
32608 var groupCount = this.cols + 1 - colSpan;
32609 // for each group potential horizontal position
32610 for ( var i = 0; i < groupCount; i++ ) {
32611 // make an array of colY values for that one group
32612 var groupColYs = this.colYs.slice( i, i + colSpan );
32613 // and get the max value of the array
32614 colGroup[i] = Math.max.apply( Math, groupColYs );
32619 _manageStamp : function( stamp )
32621 var stampSize = stamp.getSize();
32622 var offset = stamp.getBox();
32623 // get the columns that this stamp affects
32624 var firstX = this.isOriginLeft ? offset.x : offset.right;
32625 var lastX = firstX + stampSize.width;
32626 var firstCol = Math.floor( firstX / this.columnWidth );
32627 firstCol = Math.max( 0, firstCol );
32629 var lastCol = Math.floor( lastX / this.columnWidth );
32630 // lastCol should not go over if multiple of columnWidth #425
32631 lastCol -= lastX % this.columnWidth ? 0 : 1;
32632 lastCol = Math.min( this.cols - 1, lastCol );
32634 // set colYs to bottom of the stamp
32635 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32638 for ( var i = firstCol; i <= lastCol; i++ ) {
32639 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32644 _getContainerSize : function()
32646 this.maxY = Math.max.apply( Math, this.colYs );
32651 if ( this.isFitWidth ) {
32652 size.width = this._getContainerFitWidth();
32658 _getContainerFitWidth : function()
32660 var unusedCols = 0;
32661 // count unused columns
32664 if ( this.colYs[i] !== 0 ) {
32669 // fit container to columns that have been used
32670 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32673 needsResizeLayout : function()
32675 var previousWidth = this.containerWidth;
32676 this.getContainerWidth();
32677 return previousWidth !== this.containerWidth;
32692 * @class Roo.bootstrap.MasonryBrick
32693 * @extends Roo.bootstrap.Component
32694 * Bootstrap MasonryBrick class
32697 * Create a new MasonryBrick
32698 * @param {Object} config The config object
32701 Roo.bootstrap.MasonryBrick = function(config){
32703 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32705 Roo.bootstrap.MasonryBrick.register(this);
32711 * When a MasonryBrick is clcik
32712 * @param {Roo.bootstrap.MasonryBrick} this
32713 * @param {Roo.EventObject} e
32719 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32722 * @cfg {String} title
32726 * @cfg {String} html
32730 * @cfg {String} bgimage
32734 * @cfg {String} videourl
32738 * @cfg {String} cls
32742 * @cfg {String} href
32746 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32751 * @cfg {String} placetitle (center|bottom)
32756 * @cfg {Boolean} isFitContainer defalut true
32758 isFitContainer : true,
32761 * @cfg {Boolean} preventDefault defalut false
32763 preventDefault : false,
32766 * @cfg {Boolean} inverse defalut false
32768 maskInverse : false,
32770 getAutoCreate : function()
32772 if(!this.isFitContainer){
32773 return this.getSplitAutoCreate();
32776 var cls = 'masonry-brick masonry-brick-full';
32778 if(this.href.length){
32779 cls += ' masonry-brick-link';
32782 if(this.bgimage.length){
32783 cls += ' masonry-brick-image';
32786 if(this.maskInverse){
32787 cls += ' mask-inverse';
32790 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32791 cls += ' enable-mask';
32795 cls += ' masonry-' + this.size + '-brick';
32798 if(this.placetitle.length){
32800 switch (this.placetitle) {
32802 cls += ' masonry-center-title';
32805 cls += ' masonry-bottom-title';
32812 if(!this.html.length && !this.bgimage.length){
32813 cls += ' masonry-center-title';
32816 if(!this.html.length && this.bgimage.length){
32817 cls += ' masonry-bottom-title';
32822 cls += ' ' + this.cls;
32826 tag: (this.href.length) ? 'a' : 'div',
32831 cls: 'masonry-brick-mask'
32835 cls: 'masonry-brick-paragraph',
32841 if(this.href.length){
32842 cfg.href = this.href;
32845 var cn = cfg.cn[1].cn;
32847 if(this.title.length){
32850 cls: 'masonry-brick-title',
32855 if(this.html.length){
32858 cls: 'masonry-brick-text',
32863 if (!this.title.length && !this.html.length) {
32864 cfg.cn[1].cls += ' hide';
32867 if(this.bgimage.length){
32870 cls: 'masonry-brick-image-view',
32875 if(this.videourl.length){
32876 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32877 // youtube support only?
32880 cls: 'masonry-brick-image-view',
32883 allowfullscreen : true
32891 getSplitAutoCreate : function()
32893 var cls = 'masonry-brick masonry-brick-split';
32895 if(this.href.length){
32896 cls += ' masonry-brick-link';
32899 if(this.bgimage.length){
32900 cls += ' masonry-brick-image';
32904 cls += ' masonry-' + this.size + '-brick';
32907 switch (this.placetitle) {
32909 cls += ' masonry-center-title';
32912 cls += ' masonry-bottom-title';
32915 if(!this.bgimage.length){
32916 cls += ' masonry-center-title';
32919 if(this.bgimage.length){
32920 cls += ' masonry-bottom-title';
32926 cls += ' ' + this.cls;
32930 tag: (this.href.length) ? 'a' : 'div',
32935 cls: 'masonry-brick-split-head',
32939 cls: 'masonry-brick-paragraph',
32946 cls: 'masonry-brick-split-body',
32952 if(this.href.length){
32953 cfg.href = this.href;
32956 if(this.title.length){
32957 cfg.cn[0].cn[0].cn.push({
32959 cls: 'masonry-brick-title',
32964 if(this.html.length){
32965 cfg.cn[1].cn.push({
32967 cls: 'masonry-brick-text',
32972 if(this.bgimage.length){
32973 cfg.cn[0].cn.push({
32975 cls: 'masonry-brick-image-view',
32980 if(this.videourl.length){
32981 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32982 // youtube support only?
32983 cfg.cn[0].cn.cn.push({
32985 cls: 'masonry-brick-image-view',
32988 allowfullscreen : true
32995 initEvents: function()
32997 switch (this.size) {
33030 this.el.on('touchstart', this.onTouchStart, this);
33031 this.el.on('touchmove', this.onTouchMove, this);
33032 this.el.on('touchend', this.onTouchEnd, this);
33033 this.el.on('contextmenu', this.onContextMenu, this);
33035 this.el.on('mouseenter' ,this.enter, this);
33036 this.el.on('mouseleave', this.leave, this);
33037 this.el.on('click', this.onClick, this);
33040 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33041 this.parent().bricks.push(this);
33046 onClick: function(e, el)
33048 var time = this.endTimer - this.startTimer;
33049 // Roo.log(e.preventDefault());
33052 e.preventDefault();
33057 if(!this.preventDefault){
33061 e.preventDefault();
33063 if (this.activeClass != '') {
33064 this.selectBrick();
33067 this.fireEvent('click', this, e);
33070 enter: function(e, el)
33072 e.preventDefault();
33074 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33078 if(this.bgimage.length && this.html.length){
33079 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33083 leave: function(e, el)
33085 e.preventDefault();
33087 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33091 if(this.bgimage.length && this.html.length){
33092 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33096 onTouchStart: function(e, el)
33098 // e.preventDefault();
33100 this.touchmoved = false;
33102 if(!this.isFitContainer){
33106 if(!this.bgimage.length || !this.html.length){
33110 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33112 this.timer = new Date().getTime();
33116 onTouchMove: function(e, el)
33118 this.touchmoved = true;
33121 onContextMenu : function(e,el)
33123 e.preventDefault();
33124 e.stopPropagation();
33128 onTouchEnd: function(e, el)
33130 // e.preventDefault();
33132 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33139 if(!this.bgimage.length || !this.html.length){
33141 if(this.href.length){
33142 window.location.href = this.href;
33148 if(!this.isFitContainer){
33152 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33154 window.location.href = this.href;
33157 //selection on single brick only
33158 selectBrick : function() {
33160 if (!this.parentId) {
33164 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33165 var index = m.selectedBrick.indexOf(this.id);
33168 m.selectedBrick.splice(index,1);
33169 this.el.removeClass(this.activeClass);
33173 for(var i = 0; i < m.selectedBrick.length; i++) {
33174 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33175 b.el.removeClass(b.activeClass);
33178 m.selectedBrick = [];
33180 m.selectedBrick.push(this.id);
33181 this.el.addClass(this.activeClass);
33185 isSelected : function(){
33186 return this.el.hasClass(this.activeClass);
33191 Roo.apply(Roo.bootstrap.MasonryBrick, {
33194 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33196 * register a Masonry Brick
33197 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33200 register : function(brick)
33202 //this.groups[brick.id] = brick;
33203 this.groups.add(brick.id, brick);
33206 * fetch a masonry brick based on the masonry brick ID
33207 * @param {string} the masonry brick to add
33208 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33211 get: function(brick_id)
33213 // if (typeof(this.groups[brick_id]) == 'undefined') {
33216 // return this.groups[brick_id] ;
33218 if(this.groups.key(brick_id)) {
33219 return this.groups.key(brick_id);
33237 * @class Roo.bootstrap.Brick
33238 * @extends Roo.bootstrap.Component
33239 * Bootstrap Brick class
33242 * Create a new Brick
33243 * @param {Object} config The config object
33246 Roo.bootstrap.Brick = function(config){
33247 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33253 * When a Brick is click
33254 * @param {Roo.bootstrap.Brick} this
33255 * @param {Roo.EventObject} e
33261 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33264 * @cfg {String} title
33268 * @cfg {String} html
33272 * @cfg {String} bgimage
33276 * @cfg {String} cls
33280 * @cfg {String} href
33284 * @cfg {String} video
33288 * @cfg {Boolean} square
33292 getAutoCreate : function()
33294 var cls = 'roo-brick';
33296 if(this.href.length){
33297 cls += ' roo-brick-link';
33300 if(this.bgimage.length){
33301 cls += ' roo-brick-image';
33304 if(!this.html.length && !this.bgimage.length){
33305 cls += ' roo-brick-center-title';
33308 if(!this.html.length && this.bgimage.length){
33309 cls += ' roo-brick-bottom-title';
33313 cls += ' ' + this.cls;
33317 tag: (this.href.length) ? 'a' : 'div',
33322 cls: 'roo-brick-paragraph',
33328 if(this.href.length){
33329 cfg.href = this.href;
33332 var cn = cfg.cn[0].cn;
33334 if(this.title.length){
33337 cls: 'roo-brick-title',
33342 if(this.html.length){
33345 cls: 'roo-brick-text',
33352 if(this.bgimage.length){
33355 cls: 'roo-brick-image-view',
33363 initEvents: function()
33365 if(this.title.length || this.html.length){
33366 this.el.on('mouseenter' ,this.enter, this);
33367 this.el.on('mouseleave', this.leave, this);
33370 Roo.EventManager.onWindowResize(this.resize, this);
33372 if(this.bgimage.length){
33373 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33374 this.imageEl.on('load', this.onImageLoad, this);
33381 onImageLoad : function()
33386 resize : function()
33388 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33390 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33392 if(this.bgimage.length){
33393 var image = this.el.select('.roo-brick-image-view', true).first();
33395 image.setWidth(paragraph.getWidth());
33398 image.setHeight(paragraph.getWidth());
33401 this.el.setHeight(image.getHeight());
33402 paragraph.setHeight(image.getHeight());
33408 enter: function(e, el)
33410 e.preventDefault();
33412 if(this.bgimage.length){
33413 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33414 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33418 leave: function(e, el)
33420 e.preventDefault();
33422 if(this.bgimage.length){
33423 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33424 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33439 * @class Roo.bootstrap.NumberField
33440 * @extends Roo.bootstrap.Input
33441 * Bootstrap NumberField class
33447 * Create a new NumberField
33448 * @param {Object} config The config object
33451 Roo.bootstrap.NumberField = function(config){
33452 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33455 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33458 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33460 allowDecimals : true,
33462 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33464 decimalSeparator : ".",
33466 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33468 decimalPrecision : 2,
33470 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33472 allowNegative : true,
33475 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33479 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33481 minValue : Number.NEGATIVE_INFINITY,
33483 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33485 maxValue : Number.MAX_VALUE,
33487 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33489 minText : "The minimum value for this field is {0}",
33491 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33493 maxText : "The maximum value for this field is {0}",
33495 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33496 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33498 nanText : "{0} is not a valid number",
33500 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33502 thousandsDelimiter : false,
33504 * @cfg {String} valueAlign alignment of value
33506 valueAlign : "left",
33508 getAutoCreate : function()
33510 var hiddenInput = {
33514 cls: 'hidden-number-input'
33518 hiddenInput.name = this.name;
33523 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33525 this.name = hiddenInput.name;
33527 if(cfg.cn.length > 0) {
33528 cfg.cn.push(hiddenInput);
33535 initEvents : function()
33537 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33539 var allowed = "0123456789";
33541 if(this.allowDecimals){
33542 allowed += this.decimalSeparator;
33545 if(this.allowNegative){
33549 if(this.thousandsDelimiter) {
33553 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33555 var keyPress = function(e){
33557 var k = e.getKey();
33559 var c = e.getCharCode();
33562 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33563 allowed.indexOf(String.fromCharCode(c)) === -1
33569 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33573 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33578 this.el.on("keypress", keyPress, this);
33581 validateValue : function(value)
33584 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33588 var num = this.parseValue(value);
33591 this.markInvalid(String.format(this.nanText, value));
33595 if(num < this.minValue){
33596 this.markInvalid(String.format(this.minText, this.minValue));
33600 if(num > this.maxValue){
33601 this.markInvalid(String.format(this.maxText, this.maxValue));
33608 getValue : function()
33610 var v = this.hiddenEl().getValue();
33612 return this.fixPrecision(this.parseValue(v));
33615 parseValue : function(value)
33617 if(this.thousandsDelimiter) {
33619 r = new RegExp(",", "g");
33620 value = value.replace(r, "");
33623 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33624 return isNaN(value) ? '' : value;
33627 fixPrecision : function(value)
33629 if(this.thousandsDelimiter) {
33631 r = new RegExp(",", "g");
33632 value = value.replace(r, "");
33635 var nan = isNaN(value);
33637 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33638 return nan ? '' : value;
33640 return parseFloat(value).toFixed(this.decimalPrecision);
33643 setValue : function(v)
33645 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33651 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33653 this.inputEl().dom.value = (v == '') ? '' :
33654 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33656 if(!this.allowZero && v === '0') {
33657 this.hiddenEl().dom.value = '';
33658 this.inputEl().dom.value = '';
33665 decimalPrecisionFcn : function(v)
33667 return Math.floor(v);
33670 beforeBlur : function()
33672 var v = this.parseValue(this.getRawValue());
33674 if(v || v === 0 || v === ''){
33679 hiddenEl : function()
33681 return this.el.select('input.hidden-number-input',true).first();
33693 * @class Roo.bootstrap.DocumentSlider
33694 * @extends Roo.bootstrap.Component
33695 * Bootstrap DocumentSlider class
33698 * Create a new DocumentViewer
33699 * @param {Object} config The config object
33702 Roo.bootstrap.DocumentSlider = function(config){
33703 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33710 * Fire after initEvent
33711 * @param {Roo.bootstrap.DocumentSlider} this
33716 * Fire after update
33717 * @param {Roo.bootstrap.DocumentSlider} this
33723 * @param {Roo.bootstrap.DocumentSlider} this
33729 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33735 getAutoCreate : function()
33739 cls : 'roo-document-slider',
33743 cls : 'roo-document-slider-header',
33747 cls : 'roo-document-slider-header-title'
33753 cls : 'roo-document-slider-body',
33757 cls : 'roo-document-slider-prev',
33761 cls : 'fa fa-chevron-left'
33767 cls : 'roo-document-slider-thumb',
33771 cls : 'roo-document-slider-image'
33777 cls : 'roo-document-slider-next',
33781 cls : 'fa fa-chevron-right'
33793 initEvents : function()
33795 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33796 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33798 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33799 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33801 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33802 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33804 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33805 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33807 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33808 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33810 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33811 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33813 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33814 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33816 this.thumbEl.on('click', this.onClick, this);
33818 this.prevIndicator.on('click', this.prev, this);
33820 this.nextIndicator.on('click', this.next, this);
33824 initial : function()
33826 if(this.files.length){
33827 this.indicator = 1;
33831 this.fireEvent('initial', this);
33834 update : function()
33836 this.imageEl.attr('src', this.files[this.indicator - 1]);
33838 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33840 this.prevIndicator.show();
33842 if(this.indicator == 1){
33843 this.prevIndicator.hide();
33846 this.nextIndicator.show();
33848 if(this.indicator == this.files.length){
33849 this.nextIndicator.hide();
33852 this.thumbEl.scrollTo('top');
33854 this.fireEvent('update', this);
33857 onClick : function(e)
33859 e.preventDefault();
33861 this.fireEvent('click', this);
33866 e.preventDefault();
33868 this.indicator = Math.max(1, this.indicator - 1);
33875 e.preventDefault();
33877 this.indicator = Math.min(this.files.length, this.indicator + 1);
33891 * @class Roo.bootstrap.RadioSet
33892 * @extends Roo.bootstrap.Input
33893 * Bootstrap RadioSet class
33894 * @cfg {String} indicatorpos (left|right) default left
33895 * @cfg {Boolean} inline (true|false) inline the element (default true)
33896 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33898 * Create a new RadioSet
33899 * @param {Object} config The config object
33902 Roo.bootstrap.RadioSet = function(config){
33904 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33908 Roo.bootstrap.RadioSet.register(this);
33913 * Fires when the element is checked or unchecked.
33914 * @param {Roo.bootstrap.RadioSet} this This radio
33915 * @param {Roo.bootstrap.Radio} item The checked item
33920 * Fires when the element is click.
33921 * @param {Roo.bootstrap.RadioSet} this This radio set
33922 * @param {Roo.bootstrap.Radio} item The checked item
33923 * @param {Roo.EventObject} e The event object
33930 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33938 indicatorpos : 'left',
33940 getAutoCreate : function()
33944 cls : 'roo-radio-set-label',
33948 html : this.fieldLabel
33953 if(this.indicatorpos == 'left'){
33956 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33957 tooltip : 'This field is required'
33962 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33963 tooltip : 'This field is required'
33969 cls : 'roo-radio-set-items'
33972 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33974 if (align === 'left' && this.fieldLabel.length) {
33977 cls : "roo-radio-set-right",
33983 if(this.labelWidth > 12){
33984 label.style = "width: " + this.labelWidth + 'px';
33987 if(this.labelWidth < 13 && this.labelmd == 0){
33988 this.labelmd = this.labelWidth;
33991 if(this.labellg > 0){
33992 label.cls += ' col-lg-' + this.labellg;
33993 items.cls += ' col-lg-' + (12 - this.labellg);
33996 if(this.labelmd > 0){
33997 label.cls += ' col-md-' + this.labelmd;
33998 items.cls += ' col-md-' + (12 - this.labelmd);
34001 if(this.labelsm > 0){
34002 label.cls += ' col-sm-' + this.labelsm;
34003 items.cls += ' col-sm-' + (12 - this.labelsm);
34006 if(this.labelxs > 0){
34007 label.cls += ' col-xs-' + this.labelxs;
34008 items.cls += ' col-xs-' + (12 - this.labelxs);
34014 cls : 'roo-radio-set',
34018 cls : 'roo-radio-set-input',
34021 value : this.value ? this.value : ''
34028 if(this.weight.length){
34029 cfg.cls += ' roo-radio-' + this.weight;
34033 cfg.cls += ' roo-radio-set-inline';
34037 ['xs','sm','md','lg'].map(function(size){
34038 if (settings[size]) {
34039 cfg.cls += ' col-' + size + '-' + settings[size];
34047 initEvents : function()
34049 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34050 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34052 if(!this.fieldLabel.length){
34053 this.labelEl.hide();
34056 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34057 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34059 this.indicator = this.indicatorEl();
34061 if(this.indicator){
34062 this.indicator.addClass('invisible');
34065 this.originalValue = this.getValue();
34069 inputEl: function ()
34071 return this.el.select('.roo-radio-set-input', true).first();
34074 getChildContainer : function()
34076 return this.itemsEl;
34079 register : function(item)
34081 this.radioes.push(item);
34085 validate : function()
34087 if(this.getVisibilityEl().hasClass('hidden')){
34093 Roo.each(this.radioes, function(i){
34102 if(this.allowBlank) {
34106 if(this.disabled || valid){
34111 this.markInvalid();
34116 markValid : function()
34118 if(this.labelEl.isVisible(true)){
34119 this.indicatorEl().removeClass('visible');
34120 this.indicatorEl().addClass('invisible');
34123 this.el.removeClass([this.invalidClass, this.validClass]);
34124 this.el.addClass(this.validClass);
34126 this.fireEvent('valid', this);
34129 markInvalid : function(msg)
34131 if(this.allowBlank || this.disabled){
34135 if(this.labelEl.isVisible(true)){
34136 this.indicatorEl().removeClass('invisible');
34137 this.indicatorEl().addClass('visible');
34140 this.el.removeClass([this.invalidClass, this.validClass]);
34141 this.el.addClass(this.invalidClass);
34143 this.fireEvent('invalid', this, msg);
34147 setValue : function(v, suppressEvent)
34149 if(this.value === v){
34156 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34159 Roo.each(this.radioes, function(i){
34161 i.el.removeClass('checked');
34164 Roo.each(this.radioes, function(i){
34166 if(i.value === v || i.value.toString() === v.toString()){
34168 i.el.addClass('checked');
34170 if(suppressEvent !== true){
34171 this.fireEvent('check', this, i);
34182 clearInvalid : function(){
34184 if(!this.el || this.preventMark){
34188 this.el.removeClass([this.invalidClass]);
34190 this.fireEvent('valid', this);
34195 Roo.apply(Roo.bootstrap.RadioSet, {
34199 register : function(set)
34201 this.groups[set.name] = set;
34204 get: function(name)
34206 if (typeof(this.groups[name]) == 'undefined') {
34210 return this.groups[name] ;
34216 * Ext JS Library 1.1.1
34217 * Copyright(c) 2006-2007, Ext JS, LLC.
34219 * Originally Released Under LGPL - original licence link has changed is not relivant.
34222 * <script type="text/javascript">
34227 * @class Roo.bootstrap.SplitBar
34228 * @extends Roo.util.Observable
34229 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34233 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34234 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34235 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34236 split.minSize = 100;
34237 split.maxSize = 600;
34238 split.animate = true;
34239 split.on('moved', splitterMoved);
34242 * Create a new SplitBar
34243 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34244 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34245 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34246 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34247 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34248 position of the SplitBar).
34250 Roo.bootstrap.SplitBar = function(cfg){
34255 // dragElement : elm
34256 // resizingElement: el,
34258 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34259 // placement : Roo.bootstrap.SplitBar.LEFT ,
34260 // existingProxy ???
34263 this.el = Roo.get(cfg.dragElement, true);
34264 this.el.dom.unselectable = "on";
34266 this.resizingEl = Roo.get(cfg.resizingElement, true);
34270 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34271 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34274 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34277 * The minimum size of the resizing element. (Defaults to 0)
34283 * The maximum size of the resizing element. (Defaults to 2000)
34286 this.maxSize = 2000;
34289 * Whether to animate the transition to the new size
34292 this.animate = false;
34295 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34298 this.useShim = false;
34303 if(!cfg.existingProxy){
34305 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34307 this.proxy = Roo.get(cfg.existingProxy).dom;
34310 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34313 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34316 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34319 this.dragSpecs = {};
34322 * @private The adapter to use to positon and resize elements
34324 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34325 this.adapter.init(this);
34327 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34329 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34330 this.el.addClass("roo-splitbar-h");
34333 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34334 this.el.addClass("roo-splitbar-v");
34340 * Fires when the splitter is moved (alias for {@link #event-moved})
34341 * @param {Roo.bootstrap.SplitBar} this
34342 * @param {Number} newSize the new width or height
34347 * Fires when the splitter is moved
34348 * @param {Roo.bootstrap.SplitBar} this
34349 * @param {Number} newSize the new width or height
34353 * @event beforeresize
34354 * Fires before the splitter is dragged
34355 * @param {Roo.bootstrap.SplitBar} this
34357 "beforeresize" : true,
34359 "beforeapply" : true
34362 Roo.util.Observable.call(this);
34365 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34366 onStartProxyDrag : function(x, y){
34367 this.fireEvent("beforeresize", this);
34369 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34371 o.enableDisplayMode("block");
34372 // all splitbars share the same overlay
34373 Roo.bootstrap.SplitBar.prototype.overlay = o;
34375 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34376 this.overlay.show();
34377 Roo.get(this.proxy).setDisplayed("block");
34378 var size = this.adapter.getElementSize(this);
34379 this.activeMinSize = this.getMinimumSize();;
34380 this.activeMaxSize = this.getMaximumSize();;
34381 var c1 = size - this.activeMinSize;
34382 var c2 = Math.max(this.activeMaxSize - size, 0);
34383 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34384 this.dd.resetConstraints();
34385 this.dd.setXConstraint(
34386 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34387 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34389 this.dd.setYConstraint(0, 0);
34391 this.dd.resetConstraints();
34392 this.dd.setXConstraint(0, 0);
34393 this.dd.setYConstraint(
34394 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34395 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34398 this.dragSpecs.startSize = size;
34399 this.dragSpecs.startPoint = [x, y];
34400 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34404 * @private Called after the drag operation by the DDProxy
34406 onEndProxyDrag : function(e){
34407 Roo.get(this.proxy).setDisplayed(false);
34408 var endPoint = Roo.lib.Event.getXY(e);
34410 this.overlay.hide();
34413 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34414 newSize = this.dragSpecs.startSize +
34415 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34416 endPoint[0] - this.dragSpecs.startPoint[0] :
34417 this.dragSpecs.startPoint[0] - endPoint[0]
34420 newSize = this.dragSpecs.startSize +
34421 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34422 endPoint[1] - this.dragSpecs.startPoint[1] :
34423 this.dragSpecs.startPoint[1] - endPoint[1]
34426 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34427 if(newSize != this.dragSpecs.startSize){
34428 if(this.fireEvent('beforeapply', this, newSize) !== false){
34429 this.adapter.setElementSize(this, newSize);
34430 this.fireEvent("moved", this, newSize);
34431 this.fireEvent("resize", this, newSize);
34437 * Get the adapter this SplitBar uses
34438 * @return The adapter object
34440 getAdapter : function(){
34441 return this.adapter;
34445 * Set the adapter this SplitBar uses
34446 * @param {Object} adapter A SplitBar adapter object
34448 setAdapter : function(adapter){
34449 this.adapter = adapter;
34450 this.adapter.init(this);
34454 * Gets the minimum size for the resizing element
34455 * @return {Number} The minimum size
34457 getMinimumSize : function(){
34458 return this.minSize;
34462 * Sets the minimum size for the resizing element
34463 * @param {Number} minSize The minimum size
34465 setMinimumSize : function(minSize){
34466 this.minSize = minSize;
34470 * Gets the maximum size for the resizing element
34471 * @return {Number} The maximum size
34473 getMaximumSize : function(){
34474 return this.maxSize;
34478 * Sets the maximum size for the resizing element
34479 * @param {Number} maxSize The maximum size
34481 setMaximumSize : function(maxSize){
34482 this.maxSize = maxSize;
34486 * Sets the initialize size for the resizing element
34487 * @param {Number} size The initial size
34489 setCurrentSize : function(size){
34490 var oldAnimate = this.animate;
34491 this.animate = false;
34492 this.adapter.setElementSize(this, size);
34493 this.animate = oldAnimate;
34497 * Destroy this splitbar.
34498 * @param {Boolean} removeEl True to remove the element
34500 destroy : function(removeEl){
34502 this.shim.remove();
34505 this.proxy.parentNode.removeChild(this.proxy);
34513 * @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.
34515 Roo.bootstrap.SplitBar.createProxy = function(dir){
34516 var proxy = new Roo.Element(document.createElement("div"));
34517 proxy.unselectable();
34518 var cls = 'roo-splitbar-proxy';
34519 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34520 document.body.appendChild(proxy.dom);
34525 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34526 * Default Adapter. It assumes the splitter and resizing element are not positioned
34527 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34529 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34532 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34533 // do nothing for now
34534 init : function(s){
34538 * Called before drag operations to get the current size of the resizing element.
34539 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34541 getElementSize : function(s){
34542 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34543 return s.resizingEl.getWidth();
34545 return s.resizingEl.getHeight();
34550 * Called after drag operations to set the size of the resizing element.
34551 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34552 * @param {Number} newSize The new size to set
34553 * @param {Function} onComplete A function to be invoked when resizing is complete
34555 setElementSize : function(s, newSize, onComplete){
34556 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34558 s.resizingEl.setWidth(newSize);
34560 onComplete(s, newSize);
34563 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34568 s.resizingEl.setHeight(newSize);
34570 onComplete(s, newSize);
34573 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34580 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34581 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34582 * Adapter that moves the splitter element to align with the resized sizing element.
34583 * Used with an absolute positioned SplitBar.
34584 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34585 * document.body, make sure you assign an id to the body element.
34587 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34588 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34589 this.container = Roo.get(container);
34592 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34593 init : function(s){
34594 this.basic.init(s);
34597 getElementSize : function(s){
34598 return this.basic.getElementSize(s);
34601 setElementSize : function(s, newSize, onComplete){
34602 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34605 moveSplitter : function(s){
34606 var yes = Roo.bootstrap.SplitBar;
34607 switch(s.placement){
34609 s.el.setX(s.resizingEl.getRight());
34612 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34615 s.el.setY(s.resizingEl.getBottom());
34618 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34625 * Orientation constant - Create a vertical SplitBar
34629 Roo.bootstrap.SplitBar.VERTICAL = 1;
34632 * Orientation constant - Create a horizontal SplitBar
34636 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34639 * Placement constant - The resizing element is to the left of the splitter element
34643 Roo.bootstrap.SplitBar.LEFT = 1;
34646 * Placement constant - The resizing element is to the right of the splitter element
34650 Roo.bootstrap.SplitBar.RIGHT = 2;
34653 * Placement constant - The resizing element is positioned above the splitter element
34657 Roo.bootstrap.SplitBar.TOP = 3;
34660 * Placement constant - The resizing element is positioned under splitter element
34664 Roo.bootstrap.SplitBar.BOTTOM = 4;
34665 Roo.namespace("Roo.bootstrap.layout");/*
34667 * Ext JS Library 1.1.1
34668 * Copyright(c) 2006-2007, Ext JS, LLC.
34670 * Originally Released Under LGPL - original licence link has changed is not relivant.
34673 * <script type="text/javascript">
34677 * @class Roo.bootstrap.layout.Manager
34678 * @extends Roo.bootstrap.Component
34679 * Base class for layout managers.
34681 Roo.bootstrap.layout.Manager = function(config)
34683 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34689 /** false to disable window resize monitoring @type Boolean */
34690 this.monitorWindowResize = true;
34695 * Fires when a layout is performed.
34696 * @param {Roo.LayoutManager} this
34700 * @event regionresized
34701 * Fires when the user resizes a region.
34702 * @param {Roo.LayoutRegion} region The resized region
34703 * @param {Number} newSize The new size (width for east/west, height for north/south)
34705 "regionresized" : true,
34707 * @event regioncollapsed
34708 * Fires when a region is collapsed.
34709 * @param {Roo.LayoutRegion} region The collapsed region
34711 "regioncollapsed" : true,
34713 * @event regionexpanded
34714 * Fires when a region is expanded.
34715 * @param {Roo.LayoutRegion} region The expanded region
34717 "regionexpanded" : true
34719 this.updating = false;
34722 this.el = Roo.get(config.el);
34728 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34733 monitorWindowResize : true,
34739 onRender : function(ct, position)
34742 this.el = Roo.get(ct);
34745 //this.fireEvent('render',this);
34749 initEvents: function()
34753 // ie scrollbar fix
34754 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34755 document.body.scroll = "no";
34756 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34757 this.el.position('relative');
34759 this.id = this.el.id;
34760 this.el.addClass("roo-layout-container");
34761 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34762 if(this.el.dom != document.body ) {
34763 this.el.on('resize', this.layout,this);
34764 this.el.on('show', this.layout,this);
34770 * Returns true if this layout is currently being updated
34771 * @return {Boolean}
34773 isUpdating : function(){
34774 return this.updating;
34778 * Suspend the LayoutManager from doing auto-layouts while
34779 * making multiple add or remove calls
34781 beginUpdate : function(){
34782 this.updating = true;
34786 * Restore auto-layouts and optionally disable the manager from performing a layout
34787 * @param {Boolean} noLayout true to disable a layout update
34789 endUpdate : function(noLayout){
34790 this.updating = false;
34796 layout: function(){
34800 onRegionResized : function(region, newSize){
34801 this.fireEvent("regionresized", region, newSize);
34805 onRegionCollapsed : function(region){
34806 this.fireEvent("regioncollapsed", region);
34809 onRegionExpanded : function(region){
34810 this.fireEvent("regionexpanded", region);
34814 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34815 * performs box-model adjustments.
34816 * @return {Object} The size as an object {width: (the width), height: (the height)}
34818 getViewSize : function()
34821 if(this.el.dom != document.body){
34822 size = this.el.getSize();
34824 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34826 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34827 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34832 * Returns the Element this layout is bound to.
34833 * @return {Roo.Element}
34835 getEl : function(){
34840 * Returns the specified region.
34841 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34842 * @return {Roo.LayoutRegion}
34844 getRegion : function(target){
34845 return this.regions[target.toLowerCase()];
34848 onWindowResize : function(){
34849 if(this.monitorWindowResize){
34856 * Ext JS Library 1.1.1
34857 * Copyright(c) 2006-2007, Ext JS, LLC.
34859 * Originally Released Under LGPL - original licence link has changed is not relivant.
34862 * <script type="text/javascript">
34865 * @class Roo.bootstrap.layout.Border
34866 * @extends Roo.bootstrap.layout.Manager
34867 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34868 * please see: examples/bootstrap/nested.html<br><br>
34870 <b>The container the layout is rendered into can be either the body element or any other element.
34871 If it is not the body element, the container needs to either be an absolute positioned element,
34872 or you will need to add "position:relative" to the css of the container. You will also need to specify
34873 the container size if it is not the body element.</b>
34876 * Create a new Border
34877 * @param {Object} config Configuration options
34879 Roo.bootstrap.layout.Border = function(config){
34880 config = config || {};
34881 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34885 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34886 if(config[region]){
34887 config[region].region = region;
34888 this.addRegion(config[region]);
34894 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34896 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34898 * Creates and adds a new region if it doesn't already exist.
34899 * @param {String} target The target region key (north, south, east, west or center).
34900 * @param {Object} config The regions config object
34901 * @return {BorderLayoutRegion} The new region
34903 addRegion : function(config)
34905 if(!this.regions[config.region]){
34906 var r = this.factory(config);
34907 this.bindRegion(r);
34909 return this.regions[config.region];
34913 bindRegion : function(r){
34914 this.regions[r.config.region] = r;
34916 r.on("visibilitychange", this.layout, this);
34917 r.on("paneladded", this.layout, this);
34918 r.on("panelremoved", this.layout, this);
34919 r.on("invalidated", this.layout, this);
34920 r.on("resized", this.onRegionResized, this);
34921 r.on("collapsed", this.onRegionCollapsed, this);
34922 r.on("expanded", this.onRegionExpanded, this);
34926 * Performs a layout update.
34928 layout : function()
34930 if(this.updating) {
34934 // render all the rebions if they have not been done alreayd?
34935 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34936 if(this.regions[region] && !this.regions[region].bodyEl){
34937 this.regions[region].onRender(this.el)
34941 var size = this.getViewSize();
34942 var w = size.width;
34943 var h = size.height;
34948 //var x = 0, y = 0;
34950 var rs = this.regions;
34951 var north = rs["north"];
34952 var south = rs["south"];
34953 var west = rs["west"];
34954 var east = rs["east"];
34955 var center = rs["center"];
34956 //if(this.hideOnLayout){ // not supported anymore
34957 //c.el.setStyle("display", "none");
34959 if(north && north.isVisible()){
34960 var b = north.getBox();
34961 var m = north.getMargins();
34962 b.width = w - (m.left+m.right);
34965 centerY = b.height + b.y + m.bottom;
34966 centerH -= centerY;
34967 north.updateBox(this.safeBox(b));
34969 if(south && south.isVisible()){
34970 var b = south.getBox();
34971 var m = south.getMargins();
34972 b.width = w - (m.left+m.right);
34974 var totalHeight = (b.height + m.top + m.bottom);
34975 b.y = h - totalHeight + m.top;
34976 centerH -= totalHeight;
34977 south.updateBox(this.safeBox(b));
34979 if(west && west.isVisible()){
34980 var b = west.getBox();
34981 var m = west.getMargins();
34982 b.height = centerH - (m.top+m.bottom);
34984 b.y = centerY + m.top;
34985 var totalWidth = (b.width + m.left + m.right);
34986 centerX += totalWidth;
34987 centerW -= totalWidth;
34988 west.updateBox(this.safeBox(b));
34990 if(east && east.isVisible()){
34991 var b = east.getBox();
34992 var m = east.getMargins();
34993 b.height = centerH - (m.top+m.bottom);
34994 var totalWidth = (b.width + m.left + m.right);
34995 b.x = w - totalWidth + m.left;
34996 b.y = centerY + m.top;
34997 centerW -= totalWidth;
34998 east.updateBox(this.safeBox(b));
35001 var m = center.getMargins();
35003 x: centerX + m.left,
35004 y: centerY + m.top,
35005 width: centerW - (m.left+m.right),
35006 height: centerH - (m.top+m.bottom)
35008 //if(this.hideOnLayout){
35009 //center.el.setStyle("display", "block");
35011 center.updateBox(this.safeBox(centerBox));
35014 this.fireEvent("layout", this);
35018 safeBox : function(box){
35019 box.width = Math.max(0, box.width);
35020 box.height = Math.max(0, box.height);
35025 * Adds a ContentPanel (or subclass) to this layout.
35026 * @param {String} target The target region key (north, south, east, west or center).
35027 * @param {Roo.ContentPanel} panel The panel to add
35028 * @return {Roo.ContentPanel} The added panel
35030 add : function(target, panel){
35032 target = target.toLowerCase();
35033 return this.regions[target].add(panel);
35037 * Remove a ContentPanel (or subclass) to this layout.
35038 * @param {String} target The target region key (north, south, east, west or center).
35039 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35040 * @return {Roo.ContentPanel} The removed panel
35042 remove : function(target, panel){
35043 target = target.toLowerCase();
35044 return this.regions[target].remove(panel);
35048 * Searches all regions for a panel with the specified id
35049 * @param {String} panelId
35050 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35052 findPanel : function(panelId){
35053 var rs = this.regions;
35054 for(var target in rs){
35055 if(typeof rs[target] != "function"){
35056 var p = rs[target].getPanel(panelId);
35066 * Searches all regions for a panel with the specified id and activates (shows) it.
35067 * @param {String/ContentPanel} panelId The panels id or the panel itself
35068 * @return {Roo.ContentPanel} The shown panel or null
35070 showPanel : function(panelId) {
35071 var rs = this.regions;
35072 for(var target in rs){
35073 var r = rs[target];
35074 if(typeof r != "function"){
35075 if(r.hasPanel(panelId)){
35076 return r.showPanel(panelId);
35084 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35085 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35088 restoreState : function(provider){
35090 provider = Roo.state.Manager;
35092 var sm = new Roo.LayoutStateManager();
35093 sm.init(this, provider);
35099 * Adds a xtype elements to the layout.
35103 xtype : 'ContentPanel',
35110 xtype : 'NestedLayoutPanel',
35116 items : [ ... list of content panels or nested layout panels.. ]
35120 * @param {Object} cfg Xtype definition of item to add.
35122 addxtype : function(cfg)
35124 // basically accepts a pannel...
35125 // can accept a layout region..!?!?
35126 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35129 // theory? children can only be panels??
35131 //if (!cfg.xtype.match(/Panel$/)) {
35136 if (typeof(cfg.region) == 'undefined') {
35137 Roo.log("Failed to add Panel, region was not set");
35141 var region = cfg.region;
35147 xitems = cfg.items;
35154 case 'Content': // ContentPanel (el, cfg)
35155 case 'Scroll': // ContentPanel (el, cfg)
35157 cfg.autoCreate = true;
35158 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35160 // var el = this.el.createChild();
35161 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35164 this.add(region, ret);
35168 case 'TreePanel': // our new panel!
35169 cfg.el = this.el.createChild();
35170 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35171 this.add(region, ret);
35176 // create a new Layout (which is a Border Layout...
35178 var clayout = cfg.layout;
35179 clayout.el = this.el.createChild();
35180 clayout.items = clayout.items || [];
35184 // replace this exitems with the clayout ones..
35185 xitems = clayout.items;
35187 // force background off if it's in center...
35188 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35189 cfg.background = false;
35191 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35194 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35195 //console.log('adding nested layout panel ' + cfg.toSource());
35196 this.add(region, ret);
35197 nb = {}; /// find first...
35202 // needs grid and region
35204 //var el = this.getRegion(region).el.createChild();
35206 *var el = this.el.createChild();
35207 // create the grid first...
35208 cfg.grid.container = el;
35209 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35212 if (region == 'center' && this.active ) {
35213 cfg.background = false;
35216 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35218 this.add(region, ret);
35220 if (cfg.background) {
35221 // render grid on panel activation (if panel background)
35222 ret.on('activate', function(gp) {
35223 if (!gp.grid.rendered) {
35224 // gp.grid.render(el);
35228 // cfg.grid.render(el);
35234 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35235 // it was the old xcomponent building that caused this before.
35236 // espeically if border is the top element in the tree.
35246 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35248 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35249 this.add(region, ret);
35253 throw "Can not add '" + cfg.xtype + "' to Border";
35259 this.beginUpdate();
35263 Roo.each(xitems, function(i) {
35264 region = nb && i.region ? i.region : false;
35266 var add = ret.addxtype(i);
35269 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35270 if (!i.background) {
35271 abn[region] = nb[region] ;
35278 // make the last non-background panel active..
35279 //if (nb) { Roo.log(abn); }
35282 for(var r in abn) {
35283 region = this.getRegion(r);
35285 // tried using nb[r], but it does not work..
35287 region.showPanel(abn[r]);
35298 factory : function(cfg)
35301 var validRegions = Roo.bootstrap.layout.Border.regions;
35303 var target = cfg.region;
35306 var r = Roo.bootstrap.layout;
35310 return new r.North(cfg);
35312 return new r.South(cfg);
35314 return new r.East(cfg);
35316 return new r.West(cfg);
35318 return new r.Center(cfg);
35320 throw 'Layout region "'+target+'" not supported.';
35327 * Ext JS Library 1.1.1
35328 * Copyright(c) 2006-2007, Ext JS, LLC.
35330 * Originally Released Under LGPL - original licence link has changed is not relivant.
35333 * <script type="text/javascript">
35337 * @class Roo.bootstrap.layout.Basic
35338 * @extends Roo.util.Observable
35339 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35340 * and does not have a titlebar, tabs or any other features. All it does is size and position
35341 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35342 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35343 * @cfg {string} region the region that it inhabits..
35344 * @cfg {bool} skipConfig skip config?
35348 Roo.bootstrap.layout.Basic = function(config){
35350 this.mgr = config.mgr;
35352 this.position = config.region;
35354 var skipConfig = config.skipConfig;
35358 * @scope Roo.BasicLayoutRegion
35362 * @event beforeremove
35363 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35364 * @param {Roo.LayoutRegion} this
35365 * @param {Roo.ContentPanel} panel The panel
35366 * @param {Object} e The cancel event object
35368 "beforeremove" : true,
35370 * @event invalidated
35371 * Fires when the layout for this region is changed.
35372 * @param {Roo.LayoutRegion} this
35374 "invalidated" : true,
35376 * @event visibilitychange
35377 * Fires when this region is shown or hidden
35378 * @param {Roo.LayoutRegion} this
35379 * @param {Boolean} visibility true or false
35381 "visibilitychange" : true,
35383 * @event paneladded
35384 * Fires when a panel is added.
35385 * @param {Roo.LayoutRegion} this
35386 * @param {Roo.ContentPanel} panel The panel
35388 "paneladded" : true,
35390 * @event panelremoved
35391 * Fires when a panel is removed.
35392 * @param {Roo.LayoutRegion} this
35393 * @param {Roo.ContentPanel} panel The panel
35395 "panelremoved" : true,
35397 * @event beforecollapse
35398 * Fires when this region before collapse.
35399 * @param {Roo.LayoutRegion} this
35401 "beforecollapse" : true,
35404 * Fires when this region is collapsed.
35405 * @param {Roo.LayoutRegion} this
35407 "collapsed" : true,
35410 * Fires when this region is expanded.
35411 * @param {Roo.LayoutRegion} this
35416 * Fires when this region is slid into view.
35417 * @param {Roo.LayoutRegion} this
35419 "slideshow" : true,
35422 * Fires when this region slides out of view.
35423 * @param {Roo.LayoutRegion} this
35425 "slidehide" : true,
35427 * @event panelactivated
35428 * Fires when a panel is activated.
35429 * @param {Roo.LayoutRegion} this
35430 * @param {Roo.ContentPanel} panel The activated panel
35432 "panelactivated" : true,
35435 * Fires when the user resizes this region.
35436 * @param {Roo.LayoutRegion} this
35437 * @param {Number} newSize The new size (width for east/west, height for north/south)
35441 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35442 this.panels = new Roo.util.MixedCollection();
35443 this.panels.getKey = this.getPanelId.createDelegate(this);
35445 this.activePanel = null;
35446 // ensure listeners are added...
35448 if (config.listeners || config.events) {
35449 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35450 listeners : config.listeners || {},
35451 events : config.events || {}
35455 if(skipConfig !== true){
35456 this.applyConfig(config);
35460 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35462 getPanelId : function(p){
35466 applyConfig : function(config){
35467 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35468 this.config = config;
35473 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35474 * the width, for horizontal (north, south) the height.
35475 * @param {Number} newSize The new width or height
35477 resizeTo : function(newSize){
35478 var el = this.el ? this.el :
35479 (this.activePanel ? this.activePanel.getEl() : null);
35481 switch(this.position){
35484 el.setWidth(newSize);
35485 this.fireEvent("resized", this, newSize);
35489 el.setHeight(newSize);
35490 this.fireEvent("resized", this, newSize);
35496 getBox : function(){
35497 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35500 getMargins : function(){
35501 return this.margins;
35504 updateBox : function(box){
35506 var el = this.activePanel.getEl();
35507 el.dom.style.left = box.x + "px";
35508 el.dom.style.top = box.y + "px";
35509 this.activePanel.setSize(box.width, box.height);
35513 * Returns the container element for this region.
35514 * @return {Roo.Element}
35516 getEl : function(){
35517 return this.activePanel;
35521 * Returns true if this region is currently visible.
35522 * @return {Boolean}
35524 isVisible : function(){
35525 return this.activePanel ? true : false;
35528 setActivePanel : function(panel){
35529 panel = this.getPanel(panel);
35530 if(this.activePanel && this.activePanel != panel){
35531 this.activePanel.setActiveState(false);
35532 this.activePanel.getEl().setLeftTop(-10000,-10000);
35534 this.activePanel = panel;
35535 panel.setActiveState(true);
35537 panel.setSize(this.box.width, this.box.height);
35539 this.fireEvent("panelactivated", this, panel);
35540 this.fireEvent("invalidated");
35544 * Show the specified panel.
35545 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35546 * @return {Roo.ContentPanel} The shown panel or null
35548 showPanel : function(panel){
35549 panel = this.getPanel(panel);
35551 this.setActivePanel(panel);
35557 * Get the active panel for this region.
35558 * @return {Roo.ContentPanel} The active panel or null
35560 getActivePanel : function(){
35561 return this.activePanel;
35565 * Add the passed ContentPanel(s)
35566 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35567 * @return {Roo.ContentPanel} The panel added (if only one was added)
35569 add : function(panel){
35570 if(arguments.length > 1){
35571 for(var i = 0, len = arguments.length; i < len; i++) {
35572 this.add(arguments[i]);
35576 if(this.hasPanel(panel)){
35577 this.showPanel(panel);
35580 var el = panel.getEl();
35581 if(el.dom.parentNode != this.mgr.el.dom){
35582 this.mgr.el.dom.appendChild(el.dom);
35584 if(panel.setRegion){
35585 panel.setRegion(this);
35587 this.panels.add(panel);
35588 el.setStyle("position", "absolute");
35589 if(!panel.background){
35590 this.setActivePanel(panel);
35591 if(this.config.initialSize && this.panels.getCount()==1){
35592 this.resizeTo(this.config.initialSize);
35595 this.fireEvent("paneladded", this, panel);
35600 * Returns true if the panel is in this region.
35601 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35602 * @return {Boolean}
35604 hasPanel : function(panel){
35605 if(typeof panel == "object"){ // must be panel obj
35606 panel = panel.getId();
35608 return this.getPanel(panel) ? true : false;
35612 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35613 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35614 * @param {Boolean} preservePanel Overrides the config preservePanel option
35615 * @return {Roo.ContentPanel} The panel that was removed
35617 remove : function(panel, preservePanel){
35618 panel = this.getPanel(panel);
35623 this.fireEvent("beforeremove", this, panel, e);
35624 if(e.cancel === true){
35627 var panelId = panel.getId();
35628 this.panels.removeKey(panelId);
35633 * Returns the panel specified or null if it's not in this region.
35634 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35635 * @return {Roo.ContentPanel}
35637 getPanel : function(id){
35638 if(typeof id == "object"){ // must be panel obj
35641 return this.panels.get(id);
35645 * Returns this regions position (north/south/east/west/center).
35648 getPosition: function(){
35649 return this.position;
35653 * Ext JS Library 1.1.1
35654 * Copyright(c) 2006-2007, Ext JS, LLC.
35656 * Originally Released Under LGPL - original licence link has changed is not relivant.
35659 * <script type="text/javascript">
35663 * @class Roo.bootstrap.layout.Region
35664 * @extends Roo.bootstrap.layout.Basic
35665 * This class represents a region in a layout manager.
35667 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35668 * @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})
35669 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35670 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35671 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35672 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35673 * @cfg {String} title The title for the region (overrides panel titles)
35674 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35675 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35676 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35677 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35678 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35679 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35680 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35681 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35682 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35683 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35685 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35686 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35687 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35688 * @cfg {Number} width For East/West panels
35689 * @cfg {Number} height For North/South panels
35690 * @cfg {Boolean} split To show the splitter
35691 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35693 * @cfg {string} cls Extra CSS classes to add to region
35695 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35696 * @cfg {string} region the region that it inhabits..
35699 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35700 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35702 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35703 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35704 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35706 Roo.bootstrap.layout.Region = function(config)
35708 this.applyConfig(config);
35710 var mgr = config.mgr;
35711 var pos = config.region;
35712 config.skipConfig = true;
35713 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35716 this.onRender(mgr.el);
35719 this.visible = true;
35720 this.collapsed = false;
35721 this.unrendered_panels = [];
35724 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35726 position: '', // set by wrapper (eg. north/south etc..)
35727 unrendered_panels : null, // unrendered panels.
35728 createBody : function(){
35729 /** This region's body element
35730 * @type Roo.Element */
35731 this.bodyEl = this.el.createChild({
35733 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35737 onRender: function(ctr, pos)
35739 var dh = Roo.DomHelper;
35740 /** This region's container element
35741 * @type Roo.Element */
35742 this.el = dh.append(ctr.dom, {
35744 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35746 /** This region's title element
35747 * @type Roo.Element */
35749 this.titleEl = dh.append(this.el.dom,
35752 unselectable: "on",
35753 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35755 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35756 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35759 this.titleEl.enableDisplayMode();
35760 /** This region's title text element
35761 * @type HTMLElement */
35762 this.titleTextEl = this.titleEl.dom.firstChild;
35763 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35765 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35766 this.closeBtn.enableDisplayMode();
35767 this.closeBtn.on("click", this.closeClicked, this);
35768 this.closeBtn.hide();
35770 this.createBody(this.config);
35771 if(this.config.hideWhenEmpty){
35773 this.on("paneladded", this.validateVisibility, this);
35774 this.on("panelremoved", this.validateVisibility, this);
35776 if(this.autoScroll){
35777 this.bodyEl.setStyle("overflow", "auto");
35779 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35781 //if(c.titlebar !== false){
35782 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35783 this.titleEl.hide();
35785 this.titleEl.show();
35786 if(this.config.title){
35787 this.titleTextEl.innerHTML = this.config.title;
35791 if(this.config.collapsed){
35792 this.collapse(true);
35794 if(this.config.hidden){
35798 if (this.unrendered_panels && this.unrendered_panels.length) {
35799 for (var i =0;i< this.unrendered_panels.length; i++) {
35800 this.add(this.unrendered_panels[i]);
35802 this.unrendered_panels = null;
35808 applyConfig : function(c)
35811 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35812 var dh = Roo.DomHelper;
35813 if(c.titlebar !== false){
35814 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35815 this.collapseBtn.on("click", this.collapse, this);
35816 this.collapseBtn.enableDisplayMode();
35818 if(c.showPin === true || this.showPin){
35819 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35820 this.stickBtn.enableDisplayMode();
35821 this.stickBtn.on("click", this.expand, this);
35822 this.stickBtn.hide();
35827 /** This region's collapsed element
35828 * @type Roo.Element */
35831 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35832 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35835 if(c.floatable !== false){
35836 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35837 this.collapsedEl.on("click", this.collapseClick, this);
35840 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35841 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35842 id: "message", unselectable: "on", style:{"float":"left"}});
35843 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35845 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35846 this.expandBtn.on("click", this.expand, this);
35850 if(this.collapseBtn){
35851 this.collapseBtn.setVisible(c.collapsible == true);
35854 this.cmargins = c.cmargins || this.cmargins ||
35855 (this.position == "west" || this.position == "east" ?
35856 {top: 0, left: 2, right:2, bottom: 0} :
35857 {top: 2, left: 0, right:0, bottom: 2});
35859 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35862 this.bottomTabs = c.tabPosition != "top";
35864 this.autoScroll = c.autoScroll || false;
35869 this.duration = c.duration || .30;
35870 this.slideDuration = c.slideDuration || .45;
35875 * Returns true if this region is currently visible.
35876 * @return {Boolean}
35878 isVisible : function(){
35879 return this.visible;
35883 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35884 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35886 //setCollapsedTitle : function(title){
35887 // title = title || " ";
35888 // if(this.collapsedTitleTextEl){
35889 // this.collapsedTitleTextEl.innerHTML = title;
35893 getBox : function(){
35895 // if(!this.collapsed){
35896 b = this.el.getBox(false, true);
35898 // b = this.collapsedEl.getBox(false, true);
35903 getMargins : function(){
35904 return this.margins;
35905 //return this.collapsed ? this.cmargins : this.margins;
35908 highlight : function(){
35909 this.el.addClass("x-layout-panel-dragover");
35912 unhighlight : function(){
35913 this.el.removeClass("x-layout-panel-dragover");
35916 updateBox : function(box)
35918 if (!this.bodyEl) {
35919 return; // not rendered yet..
35923 if(!this.collapsed){
35924 this.el.dom.style.left = box.x + "px";
35925 this.el.dom.style.top = box.y + "px";
35926 this.updateBody(box.width, box.height);
35928 this.collapsedEl.dom.style.left = box.x + "px";
35929 this.collapsedEl.dom.style.top = box.y + "px";
35930 this.collapsedEl.setSize(box.width, box.height);
35933 this.tabs.autoSizeTabs();
35937 updateBody : function(w, h)
35940 this.el.setWidth(w);
35941 w -= this.el.getBorderWidth("rl");
35942 if(this.config.adjustments){
35943 w += this.config.adjustments[0];
35946 if(h !== null && h > 0){
35947 this.el.setHeight(h);
35948 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35949 h -= this.el.getBorderWidth("tb");
35950 if(this.config.adjustments){
35951 h += this.config.adjustments[1];
35953 this.bodyEl.setHeight(h);
35955 h = this.tabs.syncHeight(h);
35958 if(this.panelSize){
35959 w = w !== null ? w : this.panelSize.width;
35960 h = h !== null ? h : this.panelSize.height;
35962 if(this.activePanel){
35963 var el = this.activePanel.getEl();
35964 w = w !== null ? w : el.getWidth();
35965 h = h !== null ? h : el.getHeight();
35966 this.panelSize = {width: w, height: h};
35967 this.activePanel.setSize(w, h);
35969 if(Roo.isIE && this.tabs){
35970 this.tabs.el.repaint();
35975 * Returns the container element for this region.
35976 * @return {Roo.Element}
35978 getEl : function(){
35983 * Hides this region.
35986 //if(!this.collapsed){
35987 this.el.dom.style.left = "-2000px";
35990 // this.collapsedEl.dom.style.left = "-2000px";
35991 // this.collapsedEl.hide();
35993 this.visible = false;
35994 this.fireEvent("visibilitychange", this, false);
35998 * Shows this region if it was previously hidden.
36001 //if(!this.collapsed){
36004 // this.collapsedEl.show();
36006 this.visible = true;
36007 this.fireEvent("visibilitychange", this, true);
36010 closeClicked : function(){
36011 if(this.activePanel){
36012 this.remove(this.activePanel);
36016 collapseClick : function(e){
36018 e.stopPropagation();
36021 e.stopPropagation();
36027 * Collapses this region.
36028 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36031 collapse : function(skipAnim, skipCheck = false){
36032 if(this.collapsed) {
36036 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36038 this.collapsed = true;
36040 this.split.el.hide();
36042 if(this.config.animate && skipAnim !== true){
36043 this.fireEvent("invalidated", this);
36044 this.animateCollapse();
36046 this.el.setLocation(-20000,-20000);
36048 this.collapsedEl.show();
36049 this.fireEvent("collapsed", this);
36050 this.fireEvent("invalidated", this);
36056 animateCollapse : function(){
36061 * Expands this region if it was previously collapsed.
36062 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36063 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36066 expand : function(e, skipAnim){
36068 e.stopPropagation();
36070 if(!this.collapsed || this.el.hasActiveFx()) {
36074 this.afterSlideIn();
36077 this.collapsed = false;
36078 if(this.config.animate && skipAnim !== true){
36079 this.animateExpand();
36083 this.split.el.show();
36085 this.collapsedEl.setLocation(-2000,-2000);
36086 this.collapsedEl.hide();
36087 this.fireEvent("invalidated", this);
36088 this.fireEvent("expanded", this);
36092 animateExpand : function(){
36096 initTabs : function()
36098 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36100 var ts = new Roo.bootstrap.panel.Tabs({
36101 el: this.bodyEl.dom,
36102 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36103 disableTooltips: this.config.disableTabTips,
36104 toolbar : this.config.toolbar
36107 if(this.config.hideTabs){
36108 ts.stripWrap.setDisplayed(false);
36111 ts.resizeTabs = this.config.resizeTabs === true;
36112 ts.minTabWidth = this.config.minTabWidth || 40;
36113 ts.maxTabWidth = this.config.maxTabWidth || 250;
36114 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36115 ts.monitorResize = false;
36116 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36117 ts.bodyEl.addClass('roo-layout-tabs-body');
36118 this.panels.each(this.initPanelAsTab, this);
36121 initPanelAsTab : function(panel){
36122 var ti = this.tabs.addTab(
36126 this.config.closeOnTab && panel.isClosable(),
36129 if(panel.tabTip !== undefined){
36130 ti.setTooltip(panel.tabTip);
36132 ti.on("activate", function(){
36133 this.setActivePanel(panel);
36136 if(this.config.closeOnTab){
36137 ti.on("beforeclose", function(t, e){
36139 this.remove(panel);
36143 panel.tabItem = ti;
36148 updatePanelTitle : function(panel, title)
36150 if(this.activePanel == panel){
36151 this.updateTitle(title);
36154 var ti = this.tabs.getTab(panel.getEl().id);
36156 if(panel.tabTip !== undefined){
36157 ti.setTooltip(panel.tabTip);
36162 updateTitle : function(title){
36163 if(this.titleTextEl && !this.config.title){
36164 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36168 setActivePanel : function(panel)
36170 panel = this.getPanel(panel);
36171 if(this.activePanel && this.activePanel != panel){
36172 if(this.activePanel.setActiveState(false) === false){
36176 this.activePanel = panel;
36177 panel.setActiveState(true);
36178 if(this.panelSize){
36179 panel.setSize(this.panelSize.width, this.panelSize.height);
36182 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36184 this.updateTitle(panel.getTitle());
36186 this.fireEvent("invalidated", this);
36188 this.fireEvent("panelactivated", this, panel);
36192 * Shows the specified panel.
36193 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36194 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36196 showPanel : function(panel)
36198 panel = this.getPanel(panel);
36201 var tab = this.tabs.getTab(panel.getEl().id);
36202 if(tab.isHidden()){
36203 this.tabs.unhideTab(tab.id);
36207 this.setActivePanel(panel);
36214 * Get the active panel for this region.
36215 * @return {Roo.ContentPanel} The active panel or null
36217 getActivePanel : function(){
36218 return this.activePanel;
36221 validateVisibility : function(){
36222 if(this.panels.getCount() < 1){
36223 this.updateTitle(" ");
36224 this.closeBtn.hide();
36227 if(!this.isVisible()){
36234 * Adds the passed ContentPanel(s) to this region.
36235 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36236 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36238 add : function(panel)
36240 if(arguments.length > 1){
36241 for(var i = 0, len = arguments.length; i < len; i++) {
36242 this.add(arguments[i]);
36247 // if we have not been rendered yet, then we can not really do much of this..
36248 if (!this.bodyEl) {
36249 this.unrendered_panels.push(panel);
36256 if(this.hasPanel(panel)){
36257 this.showPanel(panel);
36260 panel.setRegion(this);
36261 this.panels.add(panel);
36262 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36263 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36264 // and hide them... ???
36265 this.bodyEl.dom.appendChild(panel.getEl().dom);
36266 if(panel.background !== true){
36267 this.setActivePanel(panel);
36269 this.fireEvent("paneladded", this, panel);
36276 this.initPanelAsTab(panel);
36280 if(panel.background !== true){
36281 this.tabs.activate(panel.getEl().id);
36283 this.fireEvent("paneladded", this, panel);
36288 * Hides the tab for the specified panel.
36289 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36291 hidePanel : function(panel){
36292 if(this.tabs && (panel = this.getPanel(panel))){
36293 this.tabs.hideTab(panel.getEl().id);
36298 * Unhides the tab for a previously hidden panel.
36299 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36301 unhidePanel : function(panel){
36302 if(this.tabs && (panel = this.getPanel(panel))){
36303 this.tabs.unhideTab(panel.getEl().id);
36307 clearPanels : function(){
36308 while(this.panels.getCount() > 0){
36309 this.remove(this.panels.first());
36314 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36315 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36316 * @param {Boolean} preservePanel Overrides the config preservePanel option
36317 * @return {Roo.ContentPanel} The panel that was removed
36319 remove : function(panel, preservePanel)
36321 panel = this.getPanel(panel);
36326 this.fireEvent("beforeremove", this, panel, e);
36327 if(e.cancel === true){
36330 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36331 var panelId = panel.getId();
36332 this.panels.removeKey(panelId);
36334 document.body.appendChild(panel.getEl().dom);
36337 this.tabs.removeTab(panel.getEl().id);
36338 }else if (!preservePanel){
36339 this.bodyEl.dom.removeChild(panel.getEl().dom);
36341 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36342 var p = this.panels.first();
36343 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36344 tempEl.appendChild(p.getEl().dom);
36345 this.bodyEl.update("");
36346 this.bodyEl.dom.appendChild(p.getEl().dom);
36348 this.updateTitle(p.getTitle());
36350 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36351 this.setActivePanel(p);
36353 panel.setRegion(null);
36354 if(this.activePanel == panel){
36355 this.activePanel = null;
36357 if(this.config.autoDestroy !== false && preservePanel !== true){
36358 try{panel.destroy();}catch(e){}
36360 this.fireEvent("panelremoved", this, panel);
36365 * Returns the TabPanel component used by this region
36366 * @return {Roo.TabPanel}
36368 getTabs : function(){
36372 createTool : function(parentEl, className){
36373 var btn = Roo.DomHelper.append(parentEl, {
36375 cls: "x-layout-tools-button",
36378 cls: "roo-layout-tools-button-inner " + className,
36382 btn.addClassOnOver("roo-layout-tools-button-over");
36387 * Ext JS Library 1.1.1
36388 * Copyright(c) 2006-2007, Ext JS, LLC.
36390 * Originally Released Under LGPL - original licence link has changed is not relivant.
36393 * <script type="text/javascript">
36399 * @class Roo.SplitLayoutRegion
36400 * @extends Roo.LayoutRegion
36401 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36403 Roo.bootstrap.layout.Split = function(config){
36404 this.cursor = config.cursor;
36405 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36408 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36410 splitTip : "Drag to resize.",
36411 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36412 useSplitTips : false,
36414 applyConfig : function(config){
36415 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36418 onRender : function(ctr,pos) {
36420 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36421 if(!this.config.split){
36426 var splitEl = Roo.DomHelper.append(ctr.dom, {
36428 id: this.el.id + "-split",
36429 cls: "roo-layout-split roo-layout-split-"+this.position,
36432 /** The SplitBar for this region
36433 * @type Roo.SplitBar */
36434 // does not exist yet...
36435 Roo.log([this.position, this.orientation]);
36437 this.split = new Roo.bootstrap.SplitBar({
36438 dragElement : splitEl,
36439 resizingElement: this.el,
36440 orientation : this.orientation
36443 this.split.on("moved", this.onSplitMove, this);
36444 this.split.useShim = this.config.useShim === true;
36445 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36446 if(this.useSplitTips){
36447 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36449 //if(config.collapsible){
36450 // this.split.el.on("dblclick", this.collapse, this);
36453 if(typeof this.config.minSize != "undefined"){
36454 this.split.minSize = this.config.minSize;
36456 if(typeof this.config.maxSize != "undefined"){
36457 this.split.maxSize = this.config.maxSize;
36459 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36460 this.hideSplitter();
36465 getHMaxSize : function(){
36466 var cmax = this.config.maxSize || 10000;
36467 var center = this.mgr.getRegion("center");
36468 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36471 getVMaxSize : function(){
36472 var cmax = this.config.maxSize || 10000;
36473 var center = this.mgr.getRegion("center");
36474 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36477 onSplitMove : function(split, newSize){
36478 this.fireEvent("resized", this, newSize);
36482 * Returns the {@link Roo.SplitBar} for this region.
36483 * @return {Roo.SplitBar}
36485 getSplitBar : function(){
36490 this.hideSplitter();
36491 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36494 hideSplitter : function(){
36496 this.split.el.setLocation(-2000,-2000);
36497 this.split.el.hide();
36503 this.split.el.show();
36505 Roo.bootstrap.layout.Split.superclass.show.call(this);
36508 beforeSlide: function(){
36509 if(Roo.isGecko){// firefox overflow auto bug workaround
36510 this.bodyEl.clip();
36512 this.tabs.bodyEl.clip();
36514 if(this.activePanel){
36515 this.activePanel.getEl().clip();
36517 if(this.activePanel.beforeSlide){
36518 this.activePanel.beforeSlide();
36524 afterSlide : function(){
36525 if(Roo.isGecko){// firefox overflow auto bug workaround
36526 this.bodyEl.unclip();
36528 this.tabs.bodyEl.unclip();
36530 if(this.activePanel){
36531 this.activePanel.getEl().unclip();
36532 if(this.activePanel.afterSlide){
36533 this.activePanel.afterSlide();
36539 initAutoHide : function(){
36540 if(this.autoHide !== false){
36541 if(!this.autoHideHd){
36542 var st = new Roo.util.DelayedTask(this.slideIn, this);
36543 this.autoHideHd = {
36544 "mouseout": function(e){
36545 if(!e.within(this.el, true)){
36549 "mouseover" : function(e){
36555 this.el.on(this.autoHideHd);
36559 clearAutoHide : function(){
36560 if(this.autoHide !== false){
36561 this.el.un("mouseout", this.autoHideHd.mouseout);
36562 this.el.un("mouseover", this.autoHideHd.mouseover);
36566 clearMonitor : function(){
36567 Roo.get(document).un("click", this.slideInIf, this);
36570 // these names are backwards but not changed for compat
36571 slideOut : function(){
36572 if(this.isSlid || this.el.hasActiveFx()){
36575 this.isSlid = true;
36576 if(this.collapseBtn){
36577 this.collapseBtn.hide();
36579 this.closeBtnState = this.closeBtn.getStyle('display');
36580 this.closeBtn.hide();
36582 this.stickBtn.show();
36585 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36586 this.beforeSlide();
36587 this.el.setStyle("z-index", 10001);
36588 this.el.slideIn(this.getSlideAnchor(), {
36589 callback: function(){
36591 this.initAutoHide();
36592 Roo.get(document).on("click", this.slideInIf, this);
36593 this.fireEvent("slideshow", this);
36600 afterSlideIn : function(){
36601 this.clearAutoHide();
36602 this.isSlid = false;
36603 this.clearMonitor();
36604 this.el.setStyle("z-index", "");
36605 if(this.collapseBtn){
36606 this.collapseBtn.show();
36608 this.closeBtn.setStyle('display', this.closeBtnState);
36610 this.stickBtn.hide();
36612 this.fireEvent("slidehide", this);
36615 slideIn : function(cb){
36616 if(!this.isSlid || this.el.hasActiveFx()){
36620 this.isSlid = false;
36621 this.beforeSlide();
36622 this.el.slideOut(this.getSlideAnchor(), {
36623 callback: function(){
36624 this.el.setLeftTop(-10000, -10000);
36626 this.afterSlideIn();
36634 slideInIf : function(e){
36635 if(!e.within(this.el)){
36640 animateCollapse : function(){
36641 this.beforeSlide();
36642 this.el.setStyle("z-index", 20000);
36643 var anchor = this.getSlideAnchor();
36644 this.el.slideOut(anchor, {
36645 callback : function(){
36646 this.el.setStyle("z-index", "");
36647 this.collapsedEl.slideIn(anchor, {duration:.3});
36649 this.el.setLocation(-10000,-10000);
36651 this.fireEvent("collapsed", this);
36658 animateExpand : function(){
36659 this.beforeSlide();
36660 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36661 this.el.setStyle("z-index", 20000);
36662 this.collapsedEl.hide({
36665 this.el.slideIn(this.getSlideAnchor(), {
36666 callback : function(){
36667 this.el.setStyle("z-index", "");
36670 this.split.el.show();
36672 this.fireEvent("invalidated", this);
36673 this.fireEvent("expanded", this);
36701 getAnchor : function(){
36702 return this.anchors[this.position];
36705 getCollapseAnchor : function(){
36706 return this.canchors[this.position];
36709 getSlideAnchor : function(){
36710 return this.sanchors[this.position];
36713 getAlignAdj : function(){
36714 var cm = this.cmargins;
36715 switch(this.position){
36731 getExpandAdj : function(){
36732 var c = this.collapsedEl, cm = this.cmargins;
36733 switch(this.position){
36735 return [-(cm.right+c.getWidth()+cm.left), 0];
36738 return [cm.right+c.getWidth()+cm.left, 0];
36741 return [0, -(cm.top+cm.bottom+c.getHeight())];
36744 return [0, cm.top+cm.bottom+c.getHeight()];
36750 * Ext JS Library 1.1.1
36751 * Copyright(c) 2006-2007, Ext JS, LLC.
36753 * Originally Released Under LGPL - original licence link has changed is not relivant.
36756 * <script type="text/javascript">
36759 * These classes are private internal classes
36761 Roo.bootstrap.layout.Center = function(config){
36762 config.region = "center";
36763 Roo.bootstrap.layout.Region.call(this, config);
36764 this.visible = true;
36765 this.minWidth = config.minWidth || 20;
36766 this.minHeight = config.minHeight || 20;
36769 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36771 // center panel can't be hidden
36775 // center panel can't be hidden
36778 getMinWidth: function(){
36779 return this.minWidth;
36782 getMinHeight: function(){
36783 return this.minHeight;
36796 Roo.bootstrap.layout.North = function(config)
36798 config.region = 'north';
36799 config.cursor = 'n-resize';
36801 Roo.bootstrap.layout.Split.call(this, config);
36805 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36806 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36807 this.split.el.addClass("roo-layout-split-v");
36809 var size = config.initialSize || config.height;
36810 if(typeof size != "undefined"){
36811 this.el.setHeight(size);
36814 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36816 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36820 getBox : function(){
36821 if(this.collapsed){
36822 return this.collapsedEl.getBox();
36824 var box = this.el.getBox();
36826 box.height += this.split.el.getHeight();
36831 updateBox : function(box){
36832 if(this.split && !this.collapsed){
36833 box.height -= this.split.el.getHeight();
36834 this.split.el.setLeft(box.x);
36835 this.split.el.setTop(box.y+box.height);
36836 this.split.el.setWidth(box.width);
36838 if(this.collapsed){
36839 this.updateBody(box.width, null);
36841 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36849 Roo.bootstrap.layout.South = function(config){
36850 config.region = 'south';
36851 config.cursor = 's-resize';
36852 Roo.bootstrap.layout.Split.call(this, config);
36854 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36855 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36856 this.split.el.addClass("roo-layout-split-v");
36858 var size = config.initialSize || config.height;
36859 if(typeof size != "undefined"){
36860 this.el.setHeight(size);
36864 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36865 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36866 getBox : function(){
36867 if(this.collapsed){
36868 return this.collapsedEl.getBox();
36870 var box = this.el.getBox();
36872 var sh = this.split.el.getHeight();
36879 updateBox : function(box){
36880 if(this.split && !this.collapsed){
36881 var sh = this.split.el.getHeight();
36884 this.split.el.setLeft(box.x);
36885 this.split.el.setTop(box.y-sh);
36886 this.split.el.setWidth(box.width);
36888 if(this.collapsed){
36889 this.updateBody(box.width, null);
36891 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36895 Roo.bootstrap.layout.East = function(config){
36896 config.region = "east";
36897 config.cursor = "e-resize";
36898 Roo.bootstrap.layout.Split.call(this, config);
36900 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36901 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36902 this.split.el.addClass("roo-layout-split-h");
36904 var size = config.initialSize || config.width;
36905 if(typeof size != "undefined"){
36906 this.el.setWidth(size);
36909 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36910 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36911 getBox : function(){
36912 if(this.collapsed){
36913 return this.collapsedEl.getBox();
36915 var box = this.el.getBox();
36917 var sw = this.split.el.getWidth();
36924 updateBox : function(box){
36925 if(this.split && !this.collapsed){
36926 var sw = this.split.el.getWidth();
36928 this.split.el.setLeft(box.x);
36929 this.split.el.setTop(box.y);
36930 this.split.el.setHeight(box.height);
36933 if(this.collapsed){
36934 this.updateBody(null, box.height);
36936 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36940 Roo.bootstrap.layout.West = function(config){
36941 config.region = "west";
36942 config.cursor = "w-resize";
36944 Roo.bootstrap.layout.Split.call(this, config);
36946 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36947 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36948 this.split.el.addClass("roo-layout-split-h");
36952 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36953 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36955 onRender: function(ctr, pos)
36957 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36958 var size = this.config.initialSize || this.config.width;
36959 if(typeof size != "undefined"){
36960 this.el.setWidth(size);
36964 getBox : function(){
36965 if(this.collapsed){
36966 return this.collapsedEl.getBox();
36968 var box = this.el.getBox();
36970 box.width += this.split.el.getWidth();
36975 updateBox : function(box){
36976 if(this.split && !this.collapsed){
36977 var sw = this.split.el.getWidth();
36979 this.split.el.setLeft(box.x+box.width);
36980 this.split.el.setTop(box.y);
36981 this.split.el.setHeight(box.height);
36983 if(this.collapsed){
36984 this.updateBody(null, box.height);
36986 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36989 Roo.namespace("Roo.bootstrap.panel");/*
36991 * Ext JS Library 1.1.1
36992 * Copyright(c) 2006-2007, Ext JS, LLC.
36994 * Originally Released Under LGPL - original licence link has changed is not relivant.
36997 * <script type="text/javascript">
37000 * @class Roo.ContentPanel
37001 * @extends Roo.util.Observable
37002 * A basic ContentPanel element.
37003 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37004 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37005 * @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
37006 * @cfg {Boolean} closable True if the panel can be closed/removed
37007 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37008 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37009 * @cfg {Toolbar} toolbar A toolbar for this panel
37010 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37011 * @cfg {String} title The title for this panel
37012 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37013 * @cfg {String} url Calls {@link #setUrl} with this value
37014 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37015 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37016 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37017 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37018 * @cfg {Boolean} badges render the badges
37021 * Create a new ContentPanel.
37022 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37023 * @param {String/Object} config A string to set only the title or a config object
37024 * @param {String} content (optional) Set the HTML content for this panel
37025 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37027 Roo.bootstrap.panel.Content = function( config){
37029 this.tpl = config.tpl || false;
37031 var el = config.el;
37032 var content = config.content;
37034 if(config.autoCreate){ // xtype is available if this is called from factory
37037 this.el = Roo.get(el);
37038 if(!this.el && config && config.autoCreate){
37039 if(typeof config.autoCreate == "object"){
37040 if(!config.autoCreate.id){
37041 config.autoCreate.id = config.id||el;
37043 this.el = Roo.DomHelper.append(document.body,
37044 config.autoCreate, true);
37046 var elcfg = { tag: "div",
37047 cls: "roo-layout-inactive-content",
37051 elcfg.html = config.html;
37055 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37058 this.closable = false;
37059 this.loaded = false;
37060 this.active = false;
37063 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37065 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37067 this.wrapEl = this.el; //this.el.wrap();
37069 if (config.toolbar.items) {
37070 ti = config.toolbar.items ;
37071 delete config.toolbar.items ;
37075 this.toolbar.render(this.wrapEl, 'before');
37076 for(var i =0;i < ti.length;i++) {
37077 // Roo.log(['add child', items[i]]);
37078 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37080 this.toolbar.items = nitems;
37081 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37082 delete config.toolbar;
37086 // xtype created footer. - not sure if will work as we normally have to render first..
37087 if (this.footer && !this.footer.el && this.footer.xtype) {
37088 if (!this.wrapEl) {
37089 this.wrapEl = this.el.wrap();
37092 this.footer.container = this.wrapEl.createChild();
37094 this.footer = Roo.factory(this.footer, Roo);
37099 if(typeof config == "string"){
37100 this.title = config;
37102 Roo.apply(this, config);
37106 this.resizeEl = Roo.get(this.resizeEl, true);
37108 this.resizeEl = this.el;
37110 // handle view.xtype
37118 * Fires when this panel is activated.
37119 * @param {Roo.ContentPanel} this
37123 * @event deactivate
37124 * Fires when this panel is activated.
37125 * @param {Roo.ContentPanel} this
37127 "deactivate" : true,
37131 * Fires when this panel is resized if fitToFrame is true.
37132 * @param {Roo.ContentPanel} this
37133 * @param {Number} width The width after any component adjustments
37134 * @param {Number} height The height after any component adjustments
37140 * Fires when this tab is created
37141 * @param {Roo.ContentPanel} this
37152 if(this.autoScroll){
37153 this.resizeEl.setStyle("overflow", "auto");
37155 // fix randome scrolling
37156 //this.el.on('scroll', function() {
37157 // Roo.log('fix random scolling');
37158 // this.scrollTo('top',0);
37161 content = content || this.content;
37163 this.setContent(content);
37165 if(config && config.url){
37166 this.setUrl(this.url, this.params, this.loadOnce);
37171 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37173 if (this.view && typeof(this.view.xtype) != 'undefined') {
37174 this.view.el = this.el.appendChild(document.createElement("div"));
37175 this.view = Roo.factory(this.view);
37176 this.view.render && this.view.render(false, '');
37180 this.fireEvent('render', this);
37183 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37187 setRegion : function(region){
37188 this.region = region;
37189 this.setActiveClass(region && !this.background);
37193 setActiveClass: function(state)
37196 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37197 this.el.setStyle('position','relative');
37199 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37200 this.el.setStyle('position', 'absolute');
37205 * Returns the toolbar for this Panel if one was configured.
37206 * @return {Roo.Toolbar}
37208 getToolbar : function(){
37209 return this.toolbar;
37212 setActiveState : function(active)
37214 this.active = active;
37215 this.setActiveClass(active);
37217 if(this.fireEvent("deactivate", this) === false){
37222 this.fireEvent("activate", this);
37226 * Updates this panel's element
37227 * @param {String} content The new content
37228 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37230 setContent : function(content, loadScripts){
37231 this.el.update(content, loadScripts);
37234 ignoreResize : function(w, h){
37235 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37238 this.lastSize = {width: w, height: h};
37243 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37244 * @return {Roo.UpdateManager} The UpdateManager
37246 getUpdateManager : function(){
37247 return this.el.getUpdateManager();
37250 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37251 * @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:
37254 url: "your-url.php",
37255 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37256 callback: yourFunction,
37257 scope: yourObject, //(optional scope)
37260 text: "Loading...",
37265 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37266 * 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.
37267 * @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}
37268 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37269 * @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.
37270 * @return {Roo.ContentPanel} this
37273 var um = this.el.getUpdateManager();
37274 um.update.apply(um, arguments);
37280 * 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.
37281 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37282 * @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)
37283 * @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)
37284 * @return {Roo.UpdateManager} The UpdateManager
37286 setUrl : function(url, params, loadOnce){
37287 if(this.refreshDelegate){
37288 this.removeListener("activate", this.refreshDelegate);
37290 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37291 this.on("activate", this.refreshDelegate);
37292 return this.el.getUpdateManager();
37295 _handleRefresh : function(url, params, loadOnce){
37296 if(!loadOnce || !this.loaded){
37297 var updater = this.el.getUpdateManager();
37298 updater.update(url, params, this._setLoaded.createDelegate(this));
37302 _setLoaded : function(){
37303 this.loaded = true;
37307 * Returns this panel's id
37310 getId : function(){
37315 * Returns this panel's element - used by regiosn to add.
37316 * @return {Roo.Element}
37318 getEl : function(){
37319 return this.wrapEl || this.el;
37324 adjustForComponents : function(width, height)
37326 //Roo.log('adjustForComponents ');
37327 if(this.resizeEl != this.el){
37328 width -= this.el.getFrameWidth('lr');
37329 height -= this.el.getFrameWidth('tb');
37332 var te = this.toolbar.getEl();
37333 te.setWidth(width);
37334 height -= te.getHeight();
37337 var te = this.footer.getEl();
37338 te.setWidth(width);
37339 height -= te.getHeight();
37343 if(this.adjustments){
37344 width += this.adjustments[0];
37345 height += this.adjustments[1];
37347 return {"width": width, "height": height};
37350 setSize : function(width, height){
37351 if(this.fitToFrame && !this.ignoreResize(width, height)){
37352 if(this.fitContainer && this.resizeEl != this.el){
37353 this.el.setSize(width, height);
37355 var size = this.adjustForComponents(width, height);
37356 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37357 this.fireEvent('resize', this, size.width, size.height);
37362 * Returns this panel's title
37365 getTitle : function(){
37367 if (typeof(this.title) != 'object') {
37372 for (var k in this.title) {
37373 if (!this.title.hasOwnProperty(k)) {
37377 if (k.indexOf('-') >= 0) {
37378 var s = k.split('-');
37379 for (var i = 0; i<s.length; i++) {
37380 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37383 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37390 * Set this panel's title
37391 * @param {String} title
37393 setTitle : function(title){
37394 this.title = title;
37396 this.region.updatePanelTitle(this, title);
37401 * Returns true is this panel was configured to be closable
37402 * @return {Boolean}
37404 isClosable : function(){
37405 return this.closable;
37408 beforeSlide : function(){
37410 this.resizeEl.clip();
37413 afterSlide : function(){
37415 this.resizeEl.unclip();
37419 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37420 * Will fail silently if the {@link #setUrl} method has not been called.
37421 * This does not activate the panel, just updates its content.
37423 refresh : function(){
37424 if(this.refreshDelegate){
37425 this.loaded = false;
37426 this.refreshDelegate();
37431 * Destroys this panel
37433 destroy : function(){
37434 this.el.removeAllListeners();
37435 var tempEl = document.createElement("span");
37436 tempEl.appendChild(this.el.dom);
37437 tempEl.innerHTML = "";
37443 * form - if the content panel contains a form - this is a reference to it.
37444 * @type {Roo.form.Form}
37448 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37449 * This contains a reference to it.
37455 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37465 * @param {Object} cfg Xtype definition of item to add.
37469 getChildContainer: function () {
37470 return this.getEl();
37475 var ret = new Roo.factory(cfg);
37480 if (cfg.xtype.match(/^Form$/)) {
37483 //if (this.footer) {
37484 // el = this.footer.container.insertSibling(false, 'before');
37486 el = this.el.createChild();
37489 this.form = new Roo.form.Form(cfg);
37492 if ( this.form.allItems.length) {
37493 this.form.render(el.dom);
37497 // should only have one of theses..
37498 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37499 // views.. should not be just added - used named prop 'view''
37501 cfg.el = this.el.appendChild(document.createElement("div"));
37504 var ret = new Roo.factory(cfg);
37506 ret.render && ret.render(false, ''); // render blank..
37516 * @class Roo.bootstrap.panel.Grid
37517 * @extends Roo.bootstrap.panel.Content
37519 * Create a new GridPanel.
37520 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37521 * @param {Object} config A the config object
37527 Roo.bootstrap.panel.Grid = function(config)
37531 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37532 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37534 config.el = this.wrapper;
37535 //this.el = this.wrapper;
37537 if (config.container) {
37538 // ctor'ed from a Border/panel.grid
37541 this.wrapper.setStyle("overflow", "hidden");
37542 this.wrapper.addClass('roo-grid-container');
37547 if(config.toolbar){
37548 var tool_el = this.wrapper.createChild();
37549 this.toolbar = Roo.factory(config.toolbar);
37551 if (config.toolbar.items) {
37552 ti = config.toolbar.items ;
37553 delete config.toolbar.items ;
37557 this.toolbar.render(tool_el);
37558 for(var i =0;i < ti.length;i++) {
37559 // Roo.log(['add child', items[i]]);
37560 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37562 this.toolbar.items = nitems;
37564 delete config.toolbar;
37567 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37568 config.grid.scrollBody = true;;
37569 config.grid.monitorWindowResize = false; // turn off autosizing
37570 config.grid.autoHeight = false;
37571 config.grid.autoWidth = false;
37573 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37575 if (config.background) {
37576 // render grid on panel activation (if panel background)
37577 this.on('activate', function(gp) {
37578 if (!gp.grid.rendered) {
37579 gp.grid.render(this.wrapper);
37580 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37585 this.grid.render(this.wrapper);
37586 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37589 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37590 // ??? needed ??? config.el = this.wrapper;
37595 // xtype created footer. - not sure if will work as we normally have to render first..
37596 if (this.footer && !this.footer.el && this.footer.xtype) {
37598 var ctr = this.grid.getView().getFooterPanel(true);
37599 this.footer.dataSource = this.grid.dataSource;
37600 this.footer = Roo.factory(this.footer, Roo);
37601 this.footer.render(ctr);
37611 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37612 getId : function(){
37613 return this.grid.id;
37617 * Returns the grid for this panel
37618 * @return {Roo.bootstrap.Table}
37620 getGrid : function(){
37624 setSize : function(width, height){
37625 if(!this.ignoreResize(width, height)){
37626 var grid = this.grid;
37627 var size = this.adjustForComponents(width, height);
37628 var gridel = grid.getGridEl();
37629 gridel.setSize(size.width, size.height);
37631 var thd = grid.getGridEl().select('thead',true).first();
37632 var tbd = grid.getGridEl().select('tbody', true).first();
37634 tbd.setSize(width, height - thd.getHeight());
37643 beforeSlide : function(){
37644 this.grid.getView().scroller.clip();
37647 afterSlide : function(){
37648 this.grid.getView().scroller.unclip();
37651 destroy : function(){
37652 this.grid.destroy();
37654 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37659 * @class Roo.bootstrap.panel.Nest
37660 * @extends Roo.bootstrap.panel.Content
37662 * Create a new Panel, that can contain a layout.Border.
37665 * @param {Roo.BorderLayout} layout The layout for this panel
37666 * @param {String/Object} config A string to set only the title or a config object
37668 Roo.bootstrap.panel.Nest = function(config)
37670 // construct with only one argument..
37671 /* FIXME - implement nicer consturctors
37672 if (layout.layout) {
37674 layout = config.layout;
37675 delete config.layout;
37677 if (layout.xtype && !layout.getEl) {
37678 // then layout needs constructing..
37679 layout = Roo.factory(layout, Roo);
37683 config.el = config.layout.getEl();
37685 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37687 config.layout.monitorWindowResize = false; // turn off autosizing
37688 this.layout = config.layout;
37689 this.layout.getEl().addClass("roo-layout-nested-layout");
37696 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37698 setSize : function(width, height){
37699 if(!this.ignoreResize(width, height)){
37700 var size = this.adjustForComponents(width, height);
37701 var el = this.layout.getEl();
37702 if (size.height < 1) {
37703 el.setWidth(size.width);
37705 el.setSize(size.width, size.height);
37707 var touch = el.dom.offsetWidth;
37708 this.layout.layout();
37709 // ie requires a double layout on the first pass
37710 if(Roo.isIE && !this.initialized){
37711 this.initialized = true;
37712 this.layout.layout();
37717 // activate all subpanels if not currently active..
37719 setActiveState : function(active){
37720 this.active = active;
37721 this.setActiveClass(active);
37724 this.fireEvent("deactivate", this);
37728 this.fireEvent("activate", this);
37729 // not sure if this should happen before or after..
37730 if (!this.layout) {
37731 return; // should not happen..
37734 for (var r in this.layout.regions) {
37735 reg = this.layout.getRegion(r);
37736 if (reg.getActivePanel()) {
37737 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37738 reg.setActivePanel(reg.getActivePanel());
37741 if (!reg.panels.length) {
37744 reg.showPanel(reg.getPanel(0));
37753 * Returns the nested BorderLayout for this panel
37754 * @return {Roo.BorderLayout}
37756 getLayout : function(){
37757 return this.layout;
37761 * Adds a xtype elements to the layout of the nested panel
37765 xtype : 'ContentPanel',
37772 xtype : 'NestedLayoutPanel',
37778 items : [ ... list of content panels or nested layout panels.. ]
37782 * @param {Object} cfg Xtype definition of item to add.
37784 addxtype : function(cfg) {
37785 return this.layout.addxtype(cfg);
37790 * Ext JS Library 1.1.1
37791 * Copyright(c) 2006-2007, Ext JS, LLC.
37793 * Originally Released Under LGPL - original licence link has changed is not relivant.
37796 * <script type="text/javascript">
37799 * @class Roo.TabPanel
37800 * @extends Roo.util.Observable
37801 * A lightweight tab container.
37805 // basic tabs 1, built from existing content
37806 var tabs = new Roo.TabPanel("tabs1");
37807 tabs.addTab("script", "View Script");
37808 tabs.addTab("markup", "View Markup");
37809 tabs.activate("script");
37811 // more advanced tabs, built from javascript
37812 var jtabs = new Roo.TabPanel("jtabs");
37813 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37815 // set up the UpdateManager
37816 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37817 var updater = tab2.getUpdateManager();
37818 updater.setDefaultUrl("ajax1.htm");
37819 tab2.on('activate', updater.refresh, updater, true);
37821 // Use setUrl for Ajax loading
37822 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37823 tab3.setUrl("ajax2.htm", null, true);
37826 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37829 jtabs.activate("jtabs-1");
37832 * Create a new TabPanel.
37833 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37834 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37836 Roo.bootstrap.panel.Tabs = function(config){
37838 * The container element for this TabPanel.
37839 * @type Roo.Element
37841 this.el = Roo.get(config.el);
37844 if(typeof config == "boolean"){
37845 this.tabPosition = config ? "bottom" : "top";
37847 Roo.apply(this, config);
37851 if(this.tabPosition == "bottom"){
37852 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37853 this.el.addClass("roo-tabs-bottom");
37855 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37856 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37857 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37859 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37861 if(this.tabPosition != "bottom"){
37862 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37863 * @type Roo.Element
37865 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37866 this.el.addClass("roo-tabs-top");
37870 this.bodyEl.setStyle("position", "relative");
37872 this.active = null;
37873 this.activateDelegate = this.activate.createDelegate(this);
37878 * Fires when the active tab changes
37879 * @param {Roo.TabPanel} this
37880 * @param {Roo.TabPanelItem} activePanel The new active tab
37884 * @event beforetabchange
37885 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37886 * @param {Roo.TabPanel} this
37887 * @param {Object} e Set cancel to true on this object to cancel the tab change
37888 * @param {Roo.TabPanelItem} tab The tab being changed to
37890 "beforetabchange" : true
37893 Roo.EventManager.onWindowResize(this.onResize, this);
37894 this.cpad = this.el.getPadding("lr");
37895 this.hiddenCount = 0;
37898 // toolbar on the tabbar support...
37899 if (this.toolbar) {
37900 alert("no toolbar support yet");
37901 this.toolbar = false;
37903 var tcfg = this.toolbar;
37904 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37905 this.toolbar = new Roo.Toolbar(tcfg);
37906 if (Roo.isSafari) {
37907 var tbl = tcfg.container.child('table', true);
37908 tbl.setAttribute('width', '100%');
37916 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37919 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37921 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37923 tabPosition : "top",
37925 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37927 currentTabWidth : 0,
37929 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37933 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37937 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37939 preferredTabWidth : 175,
37941 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37943 resizeTabs : false,
37945 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37947 monitorResize : true,
37949 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37954 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37955 * @param {String} id The id of the div to use <b>or create</b>
37956 * @param {String} text The text for the tab
37957 * @param {String} content (optional) Content to put in the TabPanelItem body
37958 * @param {Boolean} closable (optional) True to create a close icon on the tab
37959 * @return {Roo.TabPanelItem} The created TabPanelItem
37961 addTab : function(id, text, content, closable, tpl)
37963 var item = new Roo.bootstrap.panel.TabItem({
37967 closable : closable,
37970 this.addTabItem(item);
37972 item.setContent(content);
37978 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37979 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37980 * @return {Roo.TabPanelItem}
37982 getTab : function(id){
37983 return this.items[id];
37987 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37988 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37990 hideTab : function(id){
37991 var t = this.items[id];
37994 this.hiddenCount++;
37995 this.autoSizeTabs();
38000 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38001 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38003 unhideTab : function(id){
38004 var t = this.items[id];
38006 t.setHidden(false);
38007 this.hiddenCount--;
38008 this.autoSizeTabs();
38013 * Adds an existing {@link Roo.TabPanelItem}.
38014 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38016 addTabItem : function(item){
38017 this.items[item.id] = item;
38018 this.items.push(item);
38019 // if(this.resizeTabs){
38020 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38021 // this.autoSizeTabs();
38023 // item.autoSize();
38028 * Removes a {@link Roo.TabPanelItem}.
38029 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38031 removeTab : function(id){
38032 var items = this.items;
38033 var tab = items[id];
38034 if(!tab) { return; }
38035 var index = items.indexOf(tab);
38036 if(this.active == tab && items.length > 1){
38037 var newTab = this.getNextAvailable(index);
38042 this.stripEl.dom.removeChild(tab.pnode.dom);
38043 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38044 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38046 items.splice(index, 1);
38047 delete this.items[tab.id];
38048 tab.fireEvent("close", tab);
38049 tab.purgeListeners();
38050 this.autoSizeTabs();
38053 getNextAvailable : function(start){
38054 var items = this.items;
38056 // look for a next tab that will slide over to
38057 // replace the one being removed
38058 while(index < items.length){
38059 var item = items[++index];
38060 if(item && !item.isHidden()){
38064 // if one isn't found select the previous tab (on the left)
38067 var item = items[--index];
38068 if(item && !item.isHidden()){
38076 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38077 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38079 disableTab : function(id){
38080 var tab = this.items[id];
38081 if(tab && this.active != tab){
38087 * Enables a {@link Roo.TabPanelItem} that is disabled.
38088 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38090 enableTab : function(id){
38091 var tab = this.items[id];
38096 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38097 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38098 * @return {Roo.TabPanelItem} The TabPanelItem.
38100 activate : function(id){
38101 var tab = this.items[id];
38105 if(tab == this.active || tab.disabled){
38109 this.fireEvent("beforetabchange", this, e, tab);
38110 if(e.cancel !== true && !tab.disabled){
38112 this.active.hide();
38114 this.active = this.items[id];
38115 this.active.show();
38116 this.fireEvent("tabchange", this, this.active);
38122 * Gets the active {@link Roo.TabPanelItem}.
38123 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38125 getActiveTab : function(){
38126 return this.active;
38130 * Updates the tab body element to fit the height of the container element
38131 * for overflow scrolling
38132 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38134 syncHeight : function(targetHeight){
38135 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38136 var bm = this.bodyEl.getMargins();
38137 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38138 this.bodyEl.setHeight(newHeight);
38142 onResize : function(){
38143 if(this.monitorResize){
38144 this.autoSizeTabs();
38149 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38151 beginUpdate : function(){
38152 this.updating = true;
38156 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38158 endUpdate : function(){
38159 this.updating = false;
38160 this.autoSizeTabs();
38164 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38166 autoSizeTabs : function(){
38167 var count = this.items.length;
38168 var vcount = count - this.hiddenCount;
38169 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38172 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38173 var availWidth = Math.floor(w / vcount);
38174 var b = this.stripBody;
38175 if(b.getWidth() > w){
38176 var tabs = this.items;
38177 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38178 if(availWidth < this.minTabWidth){
38179 /*if(!this.sleft){ // incomplete scrolling code
38180 this.createScrollButtons();
38183 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38186 if(this.currentTabWidth < this.preferredTabWidth){
38187 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38193 * Returns the number of tabs in this TabPanel.
38196 getCount : function(){
38197 return this.items.length;
38201 * Resizes all the tabs to the passed width
38202 * @param {Number} The new width
38204 setTabWidth : function(width){
38205 this.currentTabWidth = width;
38206 for(var i = 0, len = this.items.length; i < len; i++) {
38207 if(!this.items[i].isHidden()) {
38208 this.items[i].setWidth(width);
38214 * Destroys this TabPanel
38215 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38217 destroy : function(removeEl){
38218 Roo.EventManager.removeResizeListener(this.onResize, this);
38219 for(var i = 0, len = this.items.length; i < len; i++){
38220 this.items[i].purgeListeners();
38222 if(removeEl === true){
38223 this.el.update("");
38228 createStrip : function(container)
38230 var strip = document.createElement("nav");
38231 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38232 container.appendChild(strip);
38236 createStripList : function(strip)
38238 // div wrapper for retard IE
38239 // returns the "tr" element.
38240 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38241 //'<div class="x-tabs-strip-wrap">'+
38242 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38243 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38244 return strip.firstChild; //.firstChild.firstChild.firstChild;
38246 createBody : function(container)
38248 var body = document.createElement("div");
38249 Roo.id(body, "tab-body");
38250 //Roo.fly(body).addClass("x-tabs-body");
38251 Roo.fly(body).addClass("tab-content");
38252 container.appendChild(body);
38255 createItemBody :function(bodyEl, id){
38256 var body = Roo.getDom(id);
38258 body = document.createElement("div");
38261 //Roo.fly(body).addClass("x-tabs-item-body");
38262 Roo.fly(body).addClass("tab-pane");
38263 bodyEl.insertBefore(body, bodyEl.firstChild);
38267 createStripElements : function(stripEl, text, closable, tpl)
38269 var td = document.createElement("li"); // was td..
38272 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38275 stripEl.appendChild(td);
38277 td.className = "x-tabs-closable";
38278 if(!this.closeTpl){
38279 this.closeTpl = new Roo.Template(
38280 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38281 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38282 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38285 var el = this.closeTpl.overwrite(td, {"text": text});
38286 var close = el.getElementsByTagName("div")[0];
38287 var inner = el.getElementsByTagName("em")[0];
38288 return {"el": el, "close": close, "inner": inner};
38291 // not sure what this is..
38292 // if(!this.tabTpl){
38293 //this.tabTpl = new Roo.Template(
38294 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38295 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38297 // this.tabTpl = new Roo.Template(
38298 // '<a href="#">' +
38299 // '<span unselectable="on"' +
38300 // (this.disableTooltips ? '' : ' title="{text}"') +
38301 // ' >{text}</span></a>'
38307 var template = tpl || this.tabTpl || false;
38311 template = new Roo.Template(
38313 '<span unselectable="on"' +
38314 (this.disableTooltips ? '' : ' title="{text}"') +
38315 ' >{text}</span></a>'
38319 switch (typeof(template)) {
38323 template = new Roo.Template(template);
38329 var el = template.overwrite(td, {"text": text});
38331 var inner = el.getElementsByTagName("span")[0];
38333 return {"el": el, "inner": inner};
38341 * @class Roo.TabPanelItem
38342 * @extends Roo.util.Observable
38343 * Represents an individual item (tab plus body) in a TabPanel.
38344 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38345 * @param {String} id The id of this TabPanelItem
38346 * @param {String} text The text for the tab of this TabPanelItem
38347 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38349 Roo.bootstrap.panel.TabItem = function(config){
38351 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38352 * @type Roo.TabPanel
38354 this.tabPanel = config.panel;
38356 * The id for this TabPanelItem
38359 this.id = config.id;
38361 this.disabled = false;
38363 this.text = config.text;
38365 this.loaded = false;
38366 this.closable = config.closable;
38369 * The body element for this TabPanelItem.
38370 * @type Roo.Element
38372 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38373 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38374 this.bodyEl.setStyle("display", "block");
38375 this.bodyEl.setStyle("zoom", "1");
38376 //this.hideAction();
38378 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38380 this.el = Roo.get(els.el);
38381 this.inner = Roo.get(els.inner, true);
38382 this.textEl = Roo.get(this.el.dom.firstChild, true);
38383 this.pnode = Roo.get(els.el.parentNode, true);
38384 // this.el.on("mousedown", this.onTabMouseDown, this);
38385 this.el.on("click", this.onTabClick, this);
38387 if(config.closable){
38388 var c = Roo.get(els.close, true);
38389 c.dom.title = this.closeText;
38390 c.addClassOnOver("close-over");
38391 c.on("click", this.closeClick, this);
38397 * Fires when this tab becomes the active tab.
38398 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38399 * @param {Roo.TabPanelItem} this
38403 * @event beforeclose
38404 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38405 * @param {Roo.TabPanelItem} this
38406 * @param {Object} e Set cancel to true on this object to cancel the close.
38408 "beforeclose": true,
38411 * Fires when this tab is closed.
38412 * @param {Roo.TabPanelItem} this
38416 * @event deactivate
38417 * Fires when this tab is no longer the active tab.
38418 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38419 * @param {Roo.TabPanelItem} this
38421 "deactivate" : true
38423 this.hidden = false;
38425 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38428 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38430 purgeListeners : function(){
38431 Roo.util.Observable.prototype.purgeListeners.call(this);
38432 this.el.removeAllListeners();
38435 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38438 this.pnode.addClass("active");
38441 this.tabPanel.stripWrap.repaint();
38443 this.fireEvent("activate", this.tabPanel, this);
38447 * Returns true if this tab is the active tab.
38448 * @return {Boolean}
38450 isActive : function(){
38451 return this.tabPanel.getActiveTab() == this;
38455 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38458 this.pnode.removeClass("active");
38460 this.fireEvent("deactivate", this.tabPanel, this);
38463 hideAction : function(){
38464 this.bodyEl.hide();
38465 this.bodyEl.setStyle("position", "absolute");
38466 this.bodyEl.setLeft("-20000px");
38467 this.bodyEl.setTop("-20000px");
38470 showAction : function(){
38471 this.bodyEl.setStyle("position", "relative");
38472 this.bodyEl.setTop("");
38473 this.bodyEl.setLeft("");
38474 this.bodyEl.show();
38478 * Set the tooltip for the tab.
38479 * @param {String} tooltip The tab's tooltip
38481 setTooltip : function(text){
38482 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38483 this.textEl.dom.qtip = text;
38484 this.textEl.dom.removeAttribute('title');
38486 this.textEl.dom.title = text;
38490 onTabClick : function(e){
38491 e.preventDefault();
38492 this.tabPanel.activate(this.id);
38495 onTabMouseDown : function(e){
38496 e.preventDefault();
38497 this.tabPanel.activate(this.id);
38500 getWidth : function(){
38501 return this.inner.getWidth();
38504 setWidth : function(width){
38505 var iwidth = width - this.pnode.getPadding("lr");
38506 this.inner.setWidth(iwidth);
38507 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38508 this.pnode.setWidth(width);
38512 * Show or hide the tab
38513 * @param {Boolean} hidden True to hide or false to show.
38515 setHidden : function(hidden){
38516 this.hidden = hidden;
38517 this.pnode.setStyle("display", hidden ? "none" : "");
38521 * Returns true if this tab is "hidden"
38522 * @return {Boolean}
38524 isHidden : function(){
38525 return this.hidden;
38529 * Returns the text for this tab
38532 getText : function(){
38536 autoSize : function(){
38537 //this.el.beginMeasure();
38538 this.textEl.setWidth(1);
38540 * #2804 [new] Tabs in Roojs
38541 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38543 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38544 //this.el.endMeasure();
38548 * Sets the text for the tab (Note: this also sets the tooltip text)
38549 * @param {String} text The tab's text and tooltip
38551 setText : function(text){
38553 this.textEl.update(text);
38554 this.setTooltip(text);
38555 //if(!this.tabPanel.resizeTabs){
38556 // this.autoSize();
38560 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38562 activate : function(){
38563 this.tabPanel.activate(this.id);
38567 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38569 disable : function(){
38570 if(this.tabPanel.active != this){
38571 this.disabled = true;
38572 this.pnode.addClass("disabled");
38577 * Enables this TabPanelItem if it was previously disabled.
38579 enable : function(){
38580 this.disabled = false;
38581 this.pnode.removeClass("disabled");
38585 * Sets the content for this TabPanelItem.
38586 * @param {String} content The content
38587 * @param {Boolean} loadScripts true to look for and load scripts
38589 setContent : function(content, loadScripts){
38590 this.bodyEl.update(content, loadScripts);
38594 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38595 * @return {Roo.UpdateManager} The UpdateManager
38597 getUpdateManager : function(){
38598 return this.bodyEl.getUpdateManager();
38602 * Set a URL to be used to load the content for this TabPanelItem.
38603 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38604 * @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)
38605 * @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)
38606 * @return {Roo.UpdateManager} The UpdateManager
38608 setUrl : function(url, params, loadOnce){
38609 if(this.refreshDelegate){
38610 this.un('activate', this.refreshDelegate);
38612 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38613 this.on("activate", this.refreshDelegate);
38614 return this.bodyEl.getUpdateManager();
38618 _handleRefresh : function(url, params, loadOnce){
38619 if(!loadOnce || !this.loaded){
38620 var updater = this.bodyEl.getUpdateManager();
38621 updater.update(url, params, this._setLoaded.createDelegate(this));
38626 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38627 * Will fail silently if the setUrl method has not been called.
38628 * This does not activate the panel, just updates its content.
38630 refresh : function(){
38631 if(this.refreshDelegate){
38632 this.loaded = false;
38633 this.refreshDelegate();
38638 _setLoaded : function(){
38639 this.loaded = true;
38643 closeClick : function(e){
38646 this.fireEvent("beforeclose", this, o);
38647 if(o.cancel !== true){
38648 this.tabPanel.removeTab(this.id);
38652 * The text displayed in the tooltip for the close icon.
38655 closeText : "Close this tab"
38658 * This script refer to:
38659 * Title: International Telephone Input
38660 * Author: Jack O'Connor
38661 * Code version: v12.1.12
38662 * Availability: https://github.com/jackocnr/intl-tel-input.git
38665 Roo.bootstrap.PhoneInputData = function() {
38668 "Afghanistan (افغانستان)",
38673 "Albania (Shqipëri)",
38678 "Algeria (الجزائر)",
38703 "Antigua and Barbuda",
38713 "Armenia (Հայաստան)",
38729 "Austria (Österreich)",
38734 "Azerbaijan (Azərbaycan)",
38744 "Bahrain (البحرين)",
38749 "Bangladesh (বাংলাদেশ)",
38759 "Belarus (Беларусь)",
38764 "Belgium (België)",
38794 "Bosnia and Herzegovina (Босна и Херцеговина)",
38809 "British Indian Ocean Territory",
38814 "British Virgin Islands",
38824 "Bulgaria (България)",
38834 "Burundi (Uburundi)",
38839 "Cambodia (កម្ពុជា)",
38844 "Cameroon (Cameroun)",
38853 ["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"]
38856 "Cape Verde (Kabu Verdi)",
38861 "Caribbean Netherlands",
38872 "Central African Republic (République centrafricaine)",
38892 "Christmas Island",
38898 "Cocos (Keeling) Islands",
38909 "Comoros (جزر القمر)",
38914 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38919 "Congo (Republic) (Congo-Brazzaville)",
38939 "Croatia (Hrvatska)",
38960 "Czech Republic (Česká republika)",
38965 "Denmark (Danmark)",
38980 "Dominican Republic (República Dominicana)",
38984 ["809", "829", "849"]
39002 "Equatorial Guinea (Guinea Ecuatorial)",
39022 "Falkland Islands (Islas Malvinas)",
39027 "Faroe Islands (Føroyar)",
39048 "French Guiana (Guyane française)",
39053 "French Polynesia (Polynésie française)",
39068 "Georgia (საქართველო)",
39073 "Germany (Deutschland)",
39093 "Greenland (Kalaallit Nunaat)",
39130 "Guinea-Bissau (Guiné Bissau)",
39155 "Hungary (Magyarország)",
39160 "Iceland (Ísland)",
39180 "Iraq (العراق)",
39196 "Israel (ישראל)",
39223 "Jordan (الأردن)",
39228 "Kazakhstan (Казахстан)",
39249 "Kuwait (الكويت)",
39254 "Kyrgyzstan (Кыргызстан)",
39264 "Latvia (Latvija)",
39269 "Lebanon (لبنان)",
39284 "Libya (ليبيا)",
39294 "Lithuania (Lietuva)",
39309 "Macedonia (FYROM) (Македонија)",
39314 "Madagascar (Madagasikara)",
39344 "Marshall Islands",
39354 "Mauritania (موريتانيا)",
39359 "Mauritius (Moris)",
39380 "Moldova (Republica Moldova)",
39390 "Mongolia (Монгол)",
39395 "Montenegro (Crna Gora)",
39405 "Morocco (المغرب)",
39411 "Mozambique (Moçambique)",
39416 "Myanmar (Burma) (မြန်မာ)",
39421 "Namibia (Namibië)",
39436 "Netherlands (Nederland)",
39441 "New Caledonia (Nouvelle-Calédonie)",
39476 "North Korea (조선 민주주의 인민 공화국)",
39481 "Northern Mariana Islands",
39497 "Pakistan (پاکستان)",
39507 "Palestine (فلسطين)",
39517 "Papua New Guinea",
39559 "Réunion (La Réunion)",
39565 "Romania (România)",
39581 "Saint Barthélemy",
39592 "Saint Kitts and Nevis",
39602 "Saint Martin (Saint-Martin (partie française))",
39608 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39613 "Saint Vincent and the Grenadines",
39628 "São Tomé and Príncipe (São Tomé e Príncipe)",
39633 "Saudi Arabia (المملكة العربية السعودية)",
39638 "Senegal (Sénégal)",
39668 "Slovakia (Slovensko)",
39673 "Slovenia (Slovenija)",
39683 "Somalia (Soomaaliya)",
39693 "South Korea (대한민국)",
39698 "South Sudan (جنوب السودان)",
39708 "Sri Lanka (ශ්රී ලංකාව)",
39713 "Sudan (السودان)",
39723 "Svalbard and Jan Mayen",
39734 "Sweden (Sverige)",
39739 "Switzerland (Schweiz)",
39744 "Syria (سوريا)",
39789 "Trinidad and Tobago",
39794 "Tunisia (تونس)",
39799 "Turkey (Türkiye)",
39809 "Turks and Caicos Islands",
39819 "U.S. Virgin Islands",
39829 "Ukraine (Україна)",
39834 "United Arab Emirates (الإمارات العربية المتحدة)",
39856 "Uzbekistan (Oʻzbekiston)",
39866 "Vatican City (Città del Vaticano)",
39877 "Vietnam (Việt Nam)",
39882 "Wallis and Futuna (Wallis-et-Futuna)",
39887 "Western Sahara (الصحراء الغربية)",
39893 "Yemen (اليمن)",
39917 * This script refer to:
39918 * Title: International Telephone Input
39919 * Author: Jack O'Connor
39920 * Code version: v12.1.12
39921 * Availability: https://github.com/jackocnr/intl-tel-input.git
39925 * @class Roo.bootstrap.PhoneInput
39926 * @extends Roo.bootstrap.TriggerField
39927 * An input with International dial-code selection
39929 * @cfg {String} defaultDialCode default '+852'
39930 * @cfg {Array} preferedCountries default []
39933 * Create a new PhoneInput.
39934 * @param {Object} config Configuration options
39937 Roo.bootstrap.PhoneInput = function(config) {
39938 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39941 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39943 listWidth: undefined,
39945 selectedClass: 'active',
39947 invalidClass : "has-warning",
39949 validClass: 'has-success',
39951 allowed: '0123456789',
39956 * @cfg {String} defaultDialCode The default dial code when initializing the input
39958 defaultDialCode: '+852',
39961 * @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
39963 preferedCountries: false,
39965 getAutoCreate : function()
39967 var data = Roo.bootstrap.PhoneInputData();
39968 var align = this.labelAlign || this.parentLabelAlign();
39971 this.allCountries = [];
39972 this.dialCodeMapping = [];
39974 for (var i = 0; i < data.length; i++) {
39976 this.allCountries[i] = {
39980 priority: c[3] || 0,
39981 areaCodes: c[4] || null
39983 this.dialCodeMapping[c[2]] = {
39986 priority: c[3] || 0,
39987 areaCodes: c[4] || null
39999 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40000 maxlength: this.max_length,
40001 cls : 'form-control tel-input',
40002 autocomplete: 'new-password'
40005 var hiddenInput = {
40008 cls: 'hidden-tel-input'
40012 hiddenInput.name = this.name;
40015 if (this.disabled) {
40016 input.disabled = true;
40019 var flag_container = {
40036 cls: this.hasFeedback ? 'has-feedback' : '',
40042 cls: 'dial-code-holder',
40049 cls: 'roo-select2-container input-group',
40056 if (this.fieldLabel.length) {
40059 tooltip: 'This field is required'
40065 cls: 'control-label',
40071 html: this.fieldLabel
40074 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40080 if(this.indicatorpos == 'right') {
40081 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40088 if(align == 'left') {
40096 if(this.labelWidth > 12){
40097 label.style = "width: " + this.labelWidth + 'px';
40099 if(this.labelWidth < 13 && this.labelmd == 0){
40100 this.labelmd = this.labelWidth;
40102 if(this.labellg > 0){
40103 label.cls += ' col-lg-' + this.labellg;
40104 input.cls += ' col-lg-' + (12 - this.labellg);
40106 if(this.labelmd > 0){
40107 label.cls += ' col-md-' + this.labelmd;
40108 container.cls += ' col-md-' + (12 - this.labelmd);
40110 if(this.labelsm > 0){
40111 label.cls += ' col-sm-' + this.labelsm;
40112 container.cls += ' col-sm-' + (12 - this.labelsm);
40114 if(this.labelxs > 0){
40115 label.cls += ' col-xs-' + this.labelxs;
40116 container.cls += ' col-xs-' + (12 - this.labelxs);
40126 var settings = this;
40128 ['xs','sm','md','lg'].map(function(size){
40129 if (settings[size]) {
40130 cfg.cls += ' col-' + size + '-' + settings[size];
40134 this.store = new Roo.data.Store({
40135 proxy : new Roo.data.MemoryProxy({}),
40136 reader : new Roo.data.JsonReader({
40147 'name' : 'dialCode',
40151 'name' : 'priority',
40155 'name' : 'areaCodes',
40162 if(!this.preferedCountries) {
40163 this.preferedCountries = [
40170 var p = this.preferedCountries.reverse();
40173 for (var i = 0; i < p.length; i++) {
40174 for (var j = 0; j < this.allCountries.length; j++) {
40175 if(this.allCountries[j].iso2 == p[i]) {
40176 var t = this.allCountries[j];
40177 this.allCountries.splice(j,1);
40178 this.allCountries.unshift(t);
40184 this.store.proxy.data = {
40186 data: this.allCountries
40192 initEvents : function()
40195 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40197 this.indicator = this.indicatorEl();
40198 this.flag = this.flagEl();
40199 this.dialCodeHolder = this.dialCodeHolderEl();
40201 this.trigger = this.el.select('div.flag-box',true).first();
40202 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40207 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40208 _this.list.setWidth(lw);
40211 this.list.on('mouseover', this.onViewOver, this);
40212 this.list.on('mousemove', this.onViewMove, this);
40213 this.inputEl().on("keyup", this.onKeyUp, this);
40214 this.inputEl().on("keypress", this.onKeyPress, this);
40216 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40218 this.view = new Roo.View(this.list, this.tpl, {
40219 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40222 this.view.on('click', this.onViewClick, this);
40223 this.setValue(this.defaultDialCode);
40226 onTriggerClick : function(e)
40228 Roo.log('trigger click');
40233 if(this.isExpanded()){
40235 this.hasFocus = false;
40237 this.store.load({});
40238 this.hasFocus = true;
40243 isExpanded : function()
40245 return this.list.isVisible();
40248 collapse : function()
40250 if(!this.isExpanded()){
40254 Roo.get(document).un('mousedown', this.collapseIf, this);
40255 Roo.get(document).un('mousewheel', this.collapseIf, this);
40256 this.fireEvent('collapse', this);
40260 expand : function()
40264 if(this.isExpanded() || !this.hasFocus){
40268 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40269 this.list.setWidth(lw);
40272 this.restrictHeight();
40274 Roo.get(document).on('mousedown', this.collapseIf, this);
40275 Roo.get(document).on('mousewheel', this.collapseIf, this);
40277 this.fireEvent('expand', this);
40280 restrictHeight : function()
40282 this.list.alignTo(this.inputEl(), this.listAlign);
40283 this.list.alignTo(this.inputEl(), this.listAlign);
40286 onViewOver : function(e, t)
40288 if(this.inKeyMode){
40291 var item = this.view.findItemFromChild(t);
40294 var index = this.view.indexOf(item);
40295 this.select(index, false);
40300 onViewClick : function(view, doFocus, el, e)
40302 var index = this.view.getSelectedIndexes()[0];
40304 var r = this.store.getAt(index);
40307 this.onSelect(r, index);
40309 if(doFocus !== false && !this.blockFocus){
40310 this.inputEl().focus();
40314 onViewMove : function(e, t)
40316 this.inKeyMode = false;
40319 select : function(index, scrollIntoView)
40321 this.selectedIndex = index;
40322 this.view.select(index);
40323 if(scrollIntoView !== false){
40324 var el = this.view.getNode(index);
40326 this.list.scrollChildIntoView(el, false);
40331 createList : function()
40333 this.list = Roo.get(document.body).createChild({
40335 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40336 style: 'display:none'
40339 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40342 collapseIf : function(e)
40344 var in_combo = e.within(this.el);
40345 var in_list = e.within(this.list);
40346 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40348 if (in_combo || in_list || is_list) {
40354 onSelect : function(record, index)
40356 if(this.fireEvent('beforeselect', this, record, index) !== false){
40358 this.setFlagClass(record.data.iso2);
40359 this.setDialCode(record.data.dialCode);
40360 this.hasFocus = false;
40362 this.fireEvent('select', this, record, index);
40366 flagEl : function()
40368 var flag = this.el.select('div.flag',true).first();
40375 dialCodeHolderEl : function()
40377 var d = this.el.select('input.dial-code-holder',true).first();
40384 setDialCode : function(v)
40386 this.dialCodeHolder.dom.value = '+'+v;
40389 setFlagClass : function(n)
40391 this.flag.dom.className = 'flag '+n;
40394 getValue : function()
40396 var v = this.inputEl().getValue();
40397 if(this.dialCodeHolder) {
40398 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40403 setValue : function(v)
40405 var d = this.getDialCode(v);
40407 //invalid dial code
40408 if(v.length == 0 || !d || d.length == 0) {
40410 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40411 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40417 this.setFlagClass(this.dialCodeMapping[d].iso2);
40418 this.setDialCode(d);
40419 this.inputEl().dom.value = v.replace('+'+d,'');
40420 this.hiddenEl().dom.value = this.getValue();
40425 getDialCode : function(v)
40429 if (v.length == 0) {
40430 return this.dialCodeHolder.dom.value;
40434 if (v.charAt(0) != "+") {
40437 var numericChars = "";
40438 for (var i = 1; i < v.length; i++) {
40439 var c = v.charAt(i);
40442 if (this.dialCodeMapping[numericChars]) {
40443 dialCode = v.substr(1, i);
40445 if (numericChars.length == 4) {
40455 this.setValue(this.defaultDialCode);
40459 hiddenEl : function()
40461 return this.el.select('input.hidden-tel-input',true).first();
40464 // after setting val
40465 onKeyUp : function(e){
40466 this.setValue(this.getValue());
40469 onKeyPress : function(e){
40470 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40477 * @class Roo.bootstrap.MoneyField
40478 * @extends Roo.bootstrap.ComboBox
40479 * Bootstrap MoneyField class
40482 * Create a new MoneyField.
40483 * @param {Object} config Configuration options
40486 Roo.bootstrap.MoneyField = function(config) {
40488 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40492 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40495 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40497 allowDecimals : true,
40499 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40501 decimalSeparator : ".",
40503 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40505 decimalPrecision : 0,
40507 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40509 allowNegative : true,
40511 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40515 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40517 minValue : Number.NEGATIVE_INFINITY,
40519 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40521 maxValue : Number.MAX_VALUE,
40523 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40525 minText : "The minimum value for this field is {0}",
40527 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40529 maxText : "The maximum value for this field is {0}",
40531 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40532 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40534 nanText : "{0} is not a valid number",
40536 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40540 * @cfg {String} defaults currency of the MoneyField
40541 * value should be in lkey
40543 defaultCurrency : false,
40545 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40547 thousandsDelimiter : false,
40549 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40560 getAutoCreate : function()
40562 var align = this.labelAlign || this.parentLabelAlign();
40574 cls : 'form-control roo-money-amount-input',
40575 autocomplete: 'new-password'
40578 var hiddenInput = {
40582 cls: 'hidden-number-input'
40585 if(this.max_length) {
40586 input.maxlength = this.max_length;
40590 hiddenInput.name = this.name;
40593 if (this.disabled) {
40594 input.disabled = true;
40597 var clg = 12 - this.inputlg;
40598 var cmd = 12 - this.inputmd;
40599 var csm = 12 - this.inputsm;
40600 var cxs = 12 - this.inputxs;
40604 cls : 'row roo-money-field',
40608 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40612 cls: 'roo-select2-container input-group',
40616 cls : 'form-control roo-money-currency-input',
40617 autocomplete: 'new-password',
40619 name : this.currencyName
40623 cls : 'input-group-addon',
40637 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40641 cls: this.hasFeedback ? 'has-feedback' : '',
40652 if (this.fieldLabel.length) {
40655 tooltip: 'This field is required'
40661 cls: 'control-label',
40667 html: this.fieldLabel
40670 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40676 if(this.indicatorpos == 'right') {
40677 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40684 if(align == 'left') {
40692 if(this.labelWidth > 12){
40693 label.style = "width: " + this.labelWidth + 'px';
40695 if(this.labelWidth < 13 && this.labelmd == 0){
40696 this.labelmd = this.labelWidth;
40698 if(this.labellg > 0){
40699 label.cls += ' col-lg-' + this.labellg;
40700 input.cls += ' col-lg-' + (12 - this.labellg);
40702 if(this.labelmd > 0){
40703 label.cls += ' col-md-' + this.labelmd;
40704 container.cls += ' col-md-' + (12 - this.labelmd);
40706 if(this.labelsm > 0){
40707 label.cls += ' col-sm-' + this.labelsm;
40708 container.cls += ' col-sm-' + (12 - this.labelsm);
40710 if(this.labelxs > 0){
40711 label.cls += ' col-xs-' + this.labelxs;
40712 container.cls += ' col-xs-' + (12 - this.labelxs);
40723 var settings = this;
40725 ['xs','sm','md','lg'].map(function(size){
40726 if (settings[size]) {
40727 cfg.cls += ' col-' + size + '-' + settings[size];
40734 initEvents : function()
40736 this.indicator = this.indicatorEl();
40738 this.initCurrencyEvent();
40740 this.initNumberEvent();
40743 initCurrencyEvent : function()
40746 throw "can not find store for combo";
40749 this.store = Roo.factory(this.store, Roo.data);
40750 this.store.parent = this;
40754 this.triggerEl = this.el.select('.input-group-addon', true).first();
40756 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40761 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40762 _this.list.setWidth(lw);
40765 this.list.on('mouseover', this.onViewOver, this);
40766 this.list.on('mousemove', this.onViewMove, this);
40767 this.list.on('scroll', this.onViewScroll, this);
40770 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40773 this.view = new Roo.View(this.list, this.tpl, {
40774 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40777 this.view.on('click', this.onViewClick, this);
40779 this.store.on('beforeload', this.onBeforeLoad, this);
40780 this.store.on('load', this.onLoad, this);
40781 this.store.on('loadexception', this.onLoadException, this);
40783 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40784 "up" : function(e){
40785 this.inKeyMode = true;
40789 "down" : function(e){
40790 if(!this.isExpanded()){
40791 this.onTriggerClick();
40793 this.inKeyMode = true;
40798 "enter" : function(e){
40801 if(this.fireEvent("specialkey", this, e)){
40802 this.onViewClick(false);
40808 "esc" : function(e){
40812 "tab" : function(e){
40815 if(this.fireEvent("specialkey", this, e)){
40816 this.onViewClick(false);
40824 doRelay : function(foo, bar, hname){
40825 if(hname == 'down' || this.scope.isExpanded()){
40826 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40834 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40838 initNumberEvent : function(e)
40840 this.inputEl().on("keydown" , this.fireKey, this);
40841 this.inputEl().on("focus", this.onFocus, this);
40842 this.inputEl().on("blur", this.onBlur, this);
40844 this.inputEl().relayEvent('keyup', this);
40846 if(this.indicator){
40847 this.indicator.addClass('invisible');
40850 this.originalValue = this.getValue();
40852 if(this.validationEvent == 'keyup'){
40853 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40854 this.inputEl().on('keyup', this.filterValidation, this);
40856 else if(this.validationEvent !== false){
40857 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40860 if(this.selectOnFocus){
40861 this.on("focus", this.preFocus, this);
40864 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40865 this.inputEl().on("keypress", this.filterKeys, this);
40867 this.inputEl().relayEvent('keypress', this);
40870 var allowed = "0123456789";
40872 if(this.allowDecimals){
40873 allowed += this.decimalSeparator;
40876 if(this.allowNegative){
40880 if(this.thousandsDelimiter) {
40884 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40886 var keyPress = function(e){
40888 var k = e.getKey();
40890 var c = e.getCharCode();
40893 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40894 allowed.indexOf(String.fromCharCode(c)) === -1
40900 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40904 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40909 this.inputEl().on("keypress", keyPress, this);
40913 onTriggerClick : function(e)
40920 this.loadNext = false;
40922 if(this.isExpanded()){
40927 this.hasFocus = true;
40929 if(this.triggerAction == 'all') {
40930 this.doQuery(this.allQuery, true);
40934 this.doQuery(this.getRawValue());
40937 getCurrency : function()
40939 var v = this.currencyEl().getValue();
40944 restrictHeight : function()
40946 this.list.alignTo(this.currencyEl(), this.listAlign);
40947 this.list.alignTo(this.currencyEl(), this.listAlign);
40950 onViewClick : function(view, doFocus, el, e)
40952 var index = this.view.getSelectedIndexes()[0];
40954 var r = this.store.getAt(index);
40957 this.onSelect(r, index);
40961 onSelect : function(record, index){
40963 if(this.fireEvent('beforeselect', this, record, index) !== false){
40965 this.setFromCurrencyData(index > -1 ? record.data : false);
40969 this.fireEvent('select', this, record, index);
40973 setFromCurrencyData : function(o)
40977 this.lastCurrency = o;
40979 if (this.currencyField) {
40980 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40982 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40985 this.lastSelectionText = currency;
40987 //setting default currency
40988 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40989 this.setCurrency(this.defaultCurrency);
40993 this.setCurrency(currency);
40996 setFromData : function(o)
41000 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41002 this.setFromCurrencyData(c);
41007 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41009 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41012 this.setValue(value);
41016 setCurrency : function(v)
41018 this.currencyValue = v;
41021 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41026 setValue : function(v)
41028 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41034 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41036 this.inputEl().dom.value = (v == '') ? '' :
41037 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41039 if(!this.allowZero && v === '0') {
41040 this.hiddenEl().dom.value = '';
41041 this.inputEl().dom.value = '';
41048 getRawValue : function()
41050 var v = this.inputEl().getValue();
41055 getValue : function()
41057 return this.fixPrecision(this.parseValue(this.getRawValue()));
41060 parseValue : function(value)
41062 if(this.thousandsDelimiter) {
41064 r = new RegExp(",", "g");
41065 value = value.replace(r, "");
41068 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41069 return isNaN(value) ? '' : value;
41073 fixPrecision : function(value)
41075 if(this.thousandsDelimiter) {
41077 r = new RegExp(",", "g");
41078 value = value.replace(r, "");
41081 var nan = isNaN(value);
41083 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41084 return nan ? '' : value;
41086 return parseFloat(value).toFixed(this.decimalPrecision);
41089 decimalPrecisionFcn : function(v)
41091 return Math.floor(v);
41094 validateValue : function(value)
41096 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41100 var num = this.parseValue(value);
41103 this.markInvalid(String.format(this.nanText, value));
41107 if(num < this.minValue){
41108 this.markInvalid(String.format(this.minText, this.minValue));
41112 if(num > this.maxValue){
41113 this.markInvalid(String.format(this.maxText, this.maxValue));
41120 validate : function()
41122 if(this.disabled || this.allowBlank){
41127 var currency = this.getCurrency();
41129 if(this.validateValue(this.getRawValue()) && currency.length){
41134 this.markInvalid();
41138 getName: function()
41143 beforeBlur : function()
41149 var v = this.parseValue(this.getRawValue());
41156 onBlur : function()
41160 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41161 //this.el.removeClass(this.focusClass);
41164 this.hasFocus = false;
41166 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41170 var v = this.getValue();
41172 if(String(v) !== String(this.startValue)){
41173 this.fireEvent('change', this, v, this.startValue);
41176 this.fireEvent("blur", this);
41179 inputEl : function()
41181 return this.el.select('.roo-money-amount-input', true).first();
41184 currencyEl : function()
41186 return this.el.select('.roo-money-currency-input', true).first();
41189 hiddenEl : function()
41191 return this.el.select('input.hidden-number-input',true).first();