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',
10387 var ibwrap = inputblock;
10392 cls: 'roo-select2-choices',
10396 cls: 'roo-select2-search-field',
10408 cls: 'roo-select2-container input-group',
10413 cls: 'form-hidden-field'
10419 if(!this.multiple && this.showToggleBtn){
10425 if (this.caret != false) {
10428 cls: 'fa fa-' + this.caret
10435 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10440 cls: 'combobox-clear',
10454 combobox.cls += ' roo-select2-container-multi';
10458 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10459 tooltip : 'This field is required'
10461 if (Roo.bootstrap.version == 4) {
10464 style : 'display:none'
10469 if (align ==='left' && this.fieldLabel.length) {
10471 cfg.cls += ' roo-form-group-label-left row';
10478 cls : 'control-label',
10479 html : this.fieldLabel
10491 var labelCfg = cfg.cn[1];
10492 var contentCfg = cfg.cn[2];
10494 if(this.indicatorpos == 'right'){
10499 cls : 'control-label',
10503 html : this.fieldLabel
10517 labelCfg = cfg.cn[0];
10518 contentCfg = cfg.cn[1];
10521 if(this.labelWidth > 12){
10522 labelCfg.style = "width: " + this.labelWidth + 'px';
10525 if(this.labelWidth < 13 && this.labelmd == 0){
10526 this.labelmd = this.labelWidth;
10529 if(this.labellg > 0){
10530 labelCfg.cls += ' col-lg-' + this.labellg;
10531 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10534 if(this.labelmd > 0){
10535 labelCfg.cls += ' col-md-' + this.labelmd;
10536 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10539 if(this.labelsm > 0){
10540 labelCfg.cls += ' col-sm-' + this.labelsm;
10541 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10544 if(this.labelxs > 0){
10545 labelCfg.cls += ' col-xs-' + this.labelxs;
10546 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10549 } else if ( this.fieldLabel.length) {
10550 // Roo.log(" label");
10555 //cls : 'input-group-addon',
10556 html : this.fieldLabel
10564 if(this.indicatorpos == 'right'){
10572 html : this.fieldLabel
10586 // Roo.log(" no label && no align");
10593 ['xs','sm','md','lg'].map(function(size){
10594 if (settings[size]) {
10595 cfg.cls += ' col-' + size + '-' + settings[size];
10606 onResize : function(w, h){
10607 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10608 // if(typeof w == 'number'){
10609 // var x = w - this.trigger.getWidth();
10610 // this.inputEl().setWidth(this.adjustWidth('input', x));
10611 // this.trigger.setStyle('left', x+'px');
10616 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10619 getResizeEl : function(){
10620 return this.inputEl();
10624 getPositionEl : function(){
10625 return this.inputEl();
10629 alignErrorIcon : function(){
10630 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10634 initEvents : function(){
10638 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10639 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10640 if(!this.multiple && this.showToggleBtn){
10641 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10642 if(this.hideTrigger){
10643 this.trigger.setDisplayed(false);
10645 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10649 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10652 if(this.removable && !this.editable && !this.tickable){
10653 var close = this.closeTriggerEl();
10656 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10657 close.on('click', this.removeBtnClick, this, close);
10661 //this.trigger.addClassOnOver('x-form-trigger-over');
10662 //this.trigger.addClassOnClick('x-form-trigger-click');
10665 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10669 closeTriggerEl : function()
10671 var close = this.el.select('.roo-combo-removable-btn', true).first();
10672 return close ? close : false;
10675 removeBtnClick : function(e, h, el)
10677 e.preventDefault();
10679 if(this.fireEvent("remove", this) !== false){
10681 this.fireEvent("afterremove", this)
10685 createList : function()
10687 this.list = Roo.get(document.body).createChild({
10689 cls: 'typeahead typeahead-long dropdown-menu',
10690 style: 'display:none'
10693 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10698 initTrigger : function(){
10703 onDestroy : function(){
10705 this.trigger.removeAllListeners();
10706 // this.trigger.remove();
10709 // this.wrap.remove();
10711 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10715 onFocus : function(){
10716 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10718 if(!this.mimicing){
10719 this.wrap.addClass('x-trigger-wrap-focus');
10720 this.mimicing = true;
10721 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10722 if(this.monitorTab){
10723 this.el.on("keydown", this.checkTab, this);
10730 checkTab : function(e){
10731 if(e.getKey() == e.TAB){
10732 this.triggerBlur();
10737 onBlur : function(){
10742 mimicBlur : function(e, t){
10744 if(!this.wrap.contains(t) && this.validateBlur()){
10745 this.triggerBlur();
10751 triggerBlur : function(){
10752 this.mimicing = false;
10753 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10754 if(this.monitorTab){
10755 this.el.un("keydown", this.checkTab, this);
10757 //this.wrap.removeClass('x-trigger-wrap-focus');
10758 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10762 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10763 validateBlur : function(e, t){
10768 onDisable : function(){
10769 this.inputEl().dom.disabled = true;
10770 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10772 // this.wrap.addClass('x-item-disabled');
10777 onEnable : function(){
10778 this.inputEl().dom.disabled = false;
10779 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10781 // this.el.removeClass('x-item-disabled');
10786 onShow : function(){
10787 var ae = this.getActionEl();
10790 ae.dom.style.display = '';
10791 ae.dom.style.visibility = 'visible';
10797 onHide : function(){
10798 var ae = this.getActionEl();
10799 ae.dom.style.display = 'none';
10803 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10804 * by an implementing function.
10806 * @param {EventObject} e
10808 onTriggerClick : Roo.emptyFn
10812 * Ext JS Library 1.1.1
10813 * Copyright(c) 2006-2007, Ext JS, LLC.
10815 * Originally Released Under LGPL - original licence link has changed is not relivant.
10818 * <script type="text/javascript">
10823 * @class Roo.data.SortTypes
10825 * Defines the default sorting (casting?) comparison functions used when sorting data.
10827 Roo.data.SortTypes = {
10829 * Default sort that does nothing
10830 * @param {Mixed} s The value being converted
10831 * @return {Mixed} The comparison value
10833 none : function(s){
10838 * The regular expression used to strip tags
10842 stripTagsRE : /<\/?[^>]+>/gi,
10845 * Strips all HTML tags to sort on text only
10846 * @param {Mixed} s The value being converted
10847 * @return {String} The comparison value
10849 asText : function(s){
10850 return String(s).replace(this.stripTagsRE, "");
10854 * Strips all HTML tags to sort on text only - Case insensitive
10855 * @param {Mixed} s The value being converted
10856 * @return {String} The comparison value
10858 asUCText : function(s){
10859 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10863 * Case insensitive string
10864 * @param {Mixed} s The value being converted
10865 * @return {String} The comparison value
10867 asUCString : function(s) {
10868 return String(s).toUpperCase();
10873 * @param {Mixed} s The value being converted
10874 * @return {Number} The comparison value
10876 asDate : function(s) {
10880 if(s instanceof Date){
10881 return s.getTime();
10883 return Date.parse(String(s));
10888 * @param {Mixed} s The value being converted
10889 * @return {Float} The comparison value
10891 asFloat : function(s) {
10892 var val = parseFloat(String(s).replace(/,/g, ""));
10901 * @param {Mixed} s The value being converted
10902 * @return {Number} The comparison value
10904 asInt : function(s) {
10905 var val = parseInt(String(s).replace(/,/g, ""));
10913 * Ext JS Library 1.1.1
10914 * Copyright(c) 2006-2007, Ext JS, LLC.
10916 * Originally Released Under LGPL - original licence link has changed is not relivant.
10919 * <script type="text/javascript">
10923 * @class Roo.data.Record
10924 * Instances of this class encapsulate both record <em>definition</em> information, and record
10925 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10926 * to access Records cached in an {@link Roo.data.Store} object.<br>
10928 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10929 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10932 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10934 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10935 * {@link #create}. The parameters are the same.
10936 * @param {Array} data An associative Array of data values keyed by the field name.
10937 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10938 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10939 * not specified an integer id is generated.
10941 Roo.data.Record = function(data, id){
10942 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10947 * Generate a constructor for a specific record layout.
10948 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10949 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10950 * Each field definition object may contain the following properties: <ul>
10951 * <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,
10952 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10953 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10954 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10955 * is being used, then this is a string containing the javascript expression to reference the data relative to
10956 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10957 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10958 * this may be omitted.</p></li>
10959 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10960 * <ul><li>auto (Default, implies no conversion)</li>
10965 * <li>date</li></ul></p></li>
10966 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10967 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10968 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10969 * by the Reader into an object that will be stored in the Record. It is passed the
10970 * following parameters:<ul>
10971 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10973 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10975 * <br>usage:<br><pre><code>
10976 var TopicRecord = Roo.data.Record.create(
10977 {name: 'title', mapping: 'topic_title'},
10978 {name: 'author', mapping: 'username'},
10979 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10980 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10981 {name: 'lastPoster', mapping: 'user2'},
10982 {name: 'excerpt', mapping: 'post_text'}
10985 var myNewRecord = new TopicRecord({
10986 title: 'Do my job please',
10989 lastPost: new Date(),
10990 lastPoster: 'Animal',
10991 excerpt: 'No way dude!'
10993 myStore.add(myNewRecord);
10998 Roo.data.Record.create = function(o){
10999 var f = function(){
11000 f.superclass.constructor.apply(this, arguments);
11002 Roo.extend(f, Roo.data.Record);
11003 var p = f.prototype;
11004 p.fields = new Roo.util.MixedCollection(false, function(field){
11007 for(var i = 0, len = o.length; i < len; i++){
11008 p.fields.add(new Roo.data.Field(o[i]));
11010 f.getField = function(name){
11011 return p.fields.get(name);
11016 Roo.data.Record.AUTO_ID = 1000;
11017 Roo.data.Record.EDIT = 'edit';
11018 Roo.data.Record.REJECT = 'reject';
11019 Roo.data.Record.COMMIT = 'commit';
11021 Roo.data.Record.prototype = {
11023 * Readonly flag - true if this record has been modified.
11032 join : function(store){
11033 this.store = store;
11037 * Set the named field to the specified value.
11038 * @param {String} name The name of the field to set.
11039 * @param {Object} value The value to set the field to.
11041 set : function(name, value){
11042 if(this.data[name] == value){
11046 if(!this.modified){
11047 this.modified = {};
11049 if(typeof this.modified[name] == 'undefined'){
11050 this.modified[name] = this.data[name];
11052 this.data[name] = value;
11053 if(!this.editing && this.store){
11054 this.store.afterEdit(this);
11059 * Get the value of the named field.
11060 * @param {String} name The name of the field to get the value of.
11061 * @return {Object} The value of the field.
11063 get : function(name){
11064 return this.data[name];
11068 beginEdit : function(){
11069 this.editing = true;
11070 this.modified = {};
11074 cancelEdit : function(){
11075 this.editing = false;
11076 delete this.modified;
11080 endEdit : function(){
11081 this.editing = false;
11082 if(this.dirty && this.store){
11083 this.store.afterEdit(this);
11088 * Usually called by the {@link Roo.data.Store} which owns the Record.
11089 * Rejects all changes made to the Record since either creation, or the last commit operation.
11090 * Modified fields are reverted to their original values.
11092 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11093 * of reject operations.
11095 reject : function(){
11096 var m = this.modified;
11098 if(typeof m[n] != "function"){
11099 this.data[n] = m[n];
11102 this.dirty = false;
11103 delete this.modified;
11104 this.editing = false;
11106 this.store.afterReject(this);
11111 * Usually called by the {@link Roo.data.Store} which owns the Record.
11112 * Commits all changes made to the Record since either creation, or the last commit operation.
11114 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11115 * of commit operations.
11117 commit : function(){
11118 this.dirty = false;
11119 delete this.modified;
11120 this.editing = false;
11122 this.store.afterCommit(this);
11127 hasError : function(){
11128 return this.error != null;
11132 clearError : function(){
11137 * Creates a copy of this record.
11138 * @param {String} id (optional) A new record id if you don't want to use this record's id
11141 copy : function(newId) {
11142 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11146 * Ext JS Library 1.1.1
11147 * Copyright(c) 2006-2007, Ext JS, LLC.
11149 * Originally Released Under LGPL - original licence link has changed is not relivant.
11152 * <script type="text/javascript">
11158 * @class Roo.data.Store
11159 * @extends Roo.util.Observable
11160 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11161 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11163 * 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
11164 * has no knowledge of the format of the data returned by the Proxy.<br>
11166 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11167 * instances from the data object. These records are cached and made available through accessor functions.
11169 * Creates a new Store.
11170 * @param {Object} config A config object containing the objects needed for the Store to access data,
11171 * and read the data into Records.
11173 Roo.data.Store = function(config){
11174 this.data = new Roo.util.MixedCollection(false);
11175 this.data.getKey = function(o){
11178 this.baseParams = {};
11180 this.paramNames = {
11185 "multisort" : "_multisort"
11188 if(config && config.data){
11189 this.inlineData = config.data;
11190 delete config.data;
11193 Roo.apply(this, config);
11195 if(this.reader){ // reader passed
11196 this.reader = Roo.factory(this.reader, Roo.data);
11197 this.reader.xmodule = this.xmodule || false;
11198 if(!this.recordType){
11199 this.recordType = this.reader.recordType;
11201 if(this.reader.onMetaChange){
11202 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11206 if(this.recordType){
11207 this.fields = this.recordType.prototype.fields;
11209 this.modified = [];
11213 * @event datachanged
11214 * Fires when the data cache has changed, and a widget which is using this Store
11215 * as a Record cache should refresh its view.
11216 * @param {Store} this
11218 datachanged : true,
11220 * @event metachange
11221 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11222 * @param {Store} this
11223 * @param {Object} meta The JSON metadata
11228 * Fires when Records have been added to the Store
11229 * @param {Store} this
11230 * @param {Roo.data.Record[]} records The array of Records added
11231 * @param {Number} index The index at which the record(s) were added
11236 * Fires when a Record has been removed from the Store
11237 * @param {Store} this
11238 * @param {Roo.data.Record} record The Record that was removed
11239 * @param {Number} index The index at which the record was removed
11244 * Fires when a Record has been updated
11245 * @param {Store} this
11246 * @param {Roo.data.Record} record The Record that was updated
11247 * @param {String} operation The update operation being performed. Value may be one of:
11249 Roo.data.Record.EDIT
11250 Roo.data.Record.REJECT
11251 Roo.data.Record.COMMIT
11257 * Fires when the data cache has been cleared.
11258 * @param {Store} this
11262 * @event beforeload
11263 * Fires before a request is made for a new data object. If the beforeload handler returns false
11264 * the load action will be canceled.
11265 * @param {Store} this
11266 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11270 * @event beforeloadadd
11271 * Fires after a new set of Records has been loaded.
11272 * @param {Store} this
11273 * @param {Roo.data.Record[]} records The Records that were loaded
11274 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11276 beforeloadadd : true,
11279 * Fires after a new set of Records has been loaded, before they are added to the store.
11280 * @param {Store} this
11281 * @param {Roo.data.Record[]} records The Records that were loaded
11282 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11283 * @params {Object} return from reader
11287 * @event loadexception
11288 * Fires if an exception occurs in the Proxy during loading.
11289 * Called with the signature of the Proxy's "loadexception" event.
11290 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11293 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11294 * @param {Object} load options
11295 * @param {Object} jsonData from your request (normally this contains the Exception)
11297 loadexception : true
11301 this.proxy = Roo.factory(this.proxy, Roo.data);
11302 this.proxy.xmodule = this.xmodule || false;
11303 this.relayEvents(this.proxy, ["loadexception"]);
11305 this.sortToggle = {};
11306 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11308 Roo.data.Store.superclass.constructor.call(this);
11310 if(this.inlineData){
11311 this.loadData(this.inlineData);
11312 delete this.inlineData;
11316 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11318 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11319 * without a remote query - used by combo/forms at present.
11323 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11326 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11329 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11330 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11333 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11334 * on any HTTP request
11337 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11340 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11344 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11345 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11347 remoteSort : false,
11350 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11351 * loaded or when a record is removed. (defaults to false).
11353 pruneModifiedRecords : false,
11356 lastOptions : null,
11359 * Add Records to the Store and fires the add event.
11360 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11362 add : function(records){
11363 records = [].concat(records);
11364 for(var i = 0, len = records.length; i < len; i++){
11365 records[i].join(this);
11367 var index = this.data.length;
11368 this.data.addAll(records);
11369 this.fireEvent("add", this, records, index);
11373 * Remove a Record from the Store and fires the remove event.
11374 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11376 remove : function(record){
11377 var index = this.data.indexOf(record);
11378 this.data.removeAt(index);
11380 if(this.pruneModifiedRecords){
11381 this.modified.remove(record);
11383 this.fireEvent("remove", this, record, index);
11387 * Remove all Records from the Store and fires the clear event.
11389 removeAll : function(){
11391 if(this.pruneModifiedRecords){
11392 this.modified = [];
11394 this.fireEvent("clear", this);
11398 * Inserts Records to the Store at the given index and fires the add event.
11399 * @param {Number} index The start index at which to insert the passed Records.
11400 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11402 insert : function(index, records){
11403 records = [].concat(records);
11404 for(var i = 0, len = records.length; i < len; i++){
11405 this.data.insert(index, records[i]);
11406 records[i].join(this);
11408 this.fireEvent("add", this, records, index);
11412 * Get the index within the cache of the passed Record.
11413 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11414 * @return {Number} The index of the passed Record. Returns -1 if not found.
11416 indexOf : function(record){
11417 return this.data.indexOf(record);
11421 * Get the index within the cache of the Record with the passed id.
11422 * @param {String} id The id of the Record to find.
11423 * @return {Number} The index of the Record. Returns -1 if not found.
11425 indexOfId : function(id){
11426 return this.data.indexOfKey(id);
11430 * Get the Record with the specified id.
11431 * @param {String} id The id of the Record to find.
11432 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11434 getById : function(id){
11435 return this.data.key(id);
11439 * Get the Record at the specified index.
11440 * @param {Number} index The index of the Record to find.
11441 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11443 getAt : function(index){
11444 return this.data.itemAt(index);
11448 * Returns a range of Records between specified indices.
11449 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11450 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11451 * @return {Roo.data.Record[]} An array of Records
11453 getRange : function(start, end){
11454 return this.data.getRange(start, end);
11458 storeOptions : function(o){
11459 o = Roo.apply({}, o);
11462 this.lastOptions = o;
11466 * Loads the Record cache from the configured Proxy using the configured Reader.
11468 * If using remote paging, then the first load call must specify the <em>start</em>
11469 * and <em>limit</em> properties in the options.params property to establish the initial
11470 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11472 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11473 * and this call will return before the new data has been loaded. Perform any post-processing
11474 * in a callback function, or in a "load" event handler.</strong>
11476 * @param {Object} options An object containing properties which control loading options:<ul>
11477 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11478 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11479 * passed the following arguments:<ul>
11480 * <li>r : Roo.data.Record[]</li>
11481 * <li>options: Options object from the load call</li>
11482 * <li>success: Boolean success indicator</li></ul></li>
11483 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11484 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11487 load : function(options){
11488 options = options || {};
11489 if(this.fireEvent("beforeload", this, options) !== false){
11490 this.storeOptions(options);
11491 var p = Roo.apply(options.params || {}, this.baseParams);
11492 // if meta was not loaded from remote source.. try requesting it.
11493 if (!this.reader.metaFromRemote) {
11494 p._requestMeta = 1;
11496 if(this.sortInfo && this.remoteSort){
11497 var pn = this.paramNames;
11498 p[pn["sort"]] = this.sortInfo.field;
11499 p[pn["dir"]] = this.sortInfo.direction;
11501 if (this.multiSort) {
11502 var pn = this.paramNames;
11503 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11506 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11511 * Reloads the Record cache from the configured Proxy using the configured Reader and
11512 * the options from the last load operation performed.
11513 * @param {Object} options (optional) An object containing properties which may override the options
11514 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11515 * the most recently used options are reused).
11517 reload : function(options){
11518 this.load(Roo.applyIf(options||{}, this.lastOptions));
11522 // Called as a callback by the Reader during a load operation.
11523 loadRecords : function(o, options, success){
11524 if(!o || success === false){
11525 if(success !== false){
11526 this.fireEvent("load", this, [], options, o);
11528 if(options.callback){
11529 options.callback.call(options.scope || this, [], options, false);
11533 // if data returned failure - throw an exception.
11534 if (o.success === false) {
11535 // show a message if no listener is registered.
11536 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11537 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11539 // loadmask wil be hooked into this..
11540 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11543 var r = o.records, t = o.totalRecords || r.length;
11545 this.fireEvent("beforeloadadd", this, r, options, o);
11547 if(!options || options.add !== true){
11548 if(this.pruneModifiedRecords){
11549 this.modified = [];
11551 for(var i = 0, len = r.length; i < len; i++){
11555 this.data = this.snapshot;
11556 delete this.snapshot;
11559 this.data.addAll(r);
11560 this.totalLength = t;
11562 this.fireEvent("datachanged", this);
11564 this.totalLength = Math.max(t, this.data.length+r.length);
11568 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11570 var e = new Roo.data.Record({});
11572 e.set(this.parent.displayField, this.parent.emptyTitle);
11573 e.set(this.parent.valueField, '');
11578 this.fireEvent("load", this, r, options, o);
11579 if(options.callback){
11580 options.callback.call(options.scope || this, r, options, true);
11586 * Loads data from a passed data block. A Reader which understands the format of the data
11587 * must have been configured in the constructor.
11588 * @param {Object} data The data block from which to read the Records. The format of the data expected
11589 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11590 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11592 loadData : function(o, append){
11593 var r = this.reader.readRecords(o);
11594 this.loadRecords(r, {add: append}, true);
11598 * Gets the number of cached records.
11600 * <em>If using paging, this may not be the total size of the dataset. If the data object
11601 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11602 * the data set size</em>
11604 getCount : function(){
11605 return this.data.length || 0;
11609 * Gets the total number of records in the dataset as returned by the server.
11611 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11612 * the dataset size</em>
11614 getTotalCount : function(){
11615 return this.totalLength || 0;
11619 * Returns the sort state of the Store as an object with two properties:
11621 field {String} The name of the field by which the Records are sorted
11622 direction {String} The sort order, "ASC" or "DESC"
11625 getSortState : function(){
11626 return this.sortInfo;
11630 applySort : function(){
11631 if(this.sortInfo && !this.remoteSort){
11632 var s = this.sortInfo, f = s.field;
11633 var st = this.fields.get(f).sortType;
11634 var fn = function(r1, r2){
11635 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11636 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11638 this.data.sort(s.direction, fn);
11639 if(this.snapshot && this.snapshot != this.data){
11640 this.snapshot.sort(s.direction, fn);
11646 * Sets the default sort column and order to be used by the next load operation.
11647 * @param {String} fieldName The name of the field to sort by.
11648 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11650 setDefaultSort : function(field, dir){
11651 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11655 * Sort the Records.
11656 * If remote sorting is used, the sort is performed on the server, and the cache is
11657 * reloaded. If local sorting is used, the cache is sorted internally.
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 sort : function(fieldName, dir){
11662 var f = this.fields.get(fieldName);
11664 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11666 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11667 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11672 this.sortToggle[f.name] = dir;
11673 this.sortInfo = {field: f.name, direction: dir};
11674 if(!this.remoteSort){
11676 this.fireEvent("datachanged", this);
11678 this.load(this.lastOptions);
11683 * Calls the specified function for each of the Records in the cache.
11684 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11685 * Returning <em>false</em> aborts and exits the iteration.
11686 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11688 each : function(fn, scope){
11689 this.data.each(fn, scope);
11693 * Gets all records modified since the last commit. Modified records are persisted across load operations
11694 * (e.g., during paging).
11695 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11697 getModifiedRecords : function(){
11698 return this.modified;
11702 createFilterFn : function(property, value, anyMatch){
11703 if(!value.exec){ // not a regex
11704 value = String(value);
11705 if(value.length == 0){
11708 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11710 return function(r){
11711 return value.test(r.data[property]);
11716 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11717 * @param {String} property A field on your records
11718 * @param {Number} start The record index to start at (defaults to 0)
11719 * @param {Number} end The last record index to include (defaults to length - 1)
11720 * @return {Number} The sum
11722 sum : function(property, start, end){
11723 var rs = this.data.items, v = 0;
11724 start = start || 0;
11725 end = (end || end === 0) ? end : rs.length-1;
11727 for(var i = start; i <= end; i++){
11728 v += (rs[i].data[property] || 0);
11734 * Filter the records by a specified property.
11735 * @param {String} field A field on your records
11736 * @param {String/RegExp} value Either a string that the field
11737 * should start with or a RegExp to test against the field
11738 * @param {Boolean} anyMatch True to match any part not just the beginning
11740 filter : function(property, value, anyMatch){
11741 var fn = this.createFilterFn(property, value, anyMatch);
11742 return fn ? this.filterBy(fn) : this.clearFilter();
11746 * Filter by a function. The specified function will be called with each
11747 * record in this data source. If the function returns true the record is included,
11748 * otherwise it is filtered.
11749 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11750 * @param {Object} scope (optional) The scope of the function (defaults to this)
11752 filterBy : function(fn, scope){
11753 this.snapshot = this.snapshot || this.data;
11754 this.data = this.queryBy(fn, scope||this);
11755 this.fireEvent("datachanged", this);
11759 * Query the records by a specified property.
11760 * @param {String} field A field on your records
11761 * @param {String/RegExp} value Either a string that the field
11762 * should start with or a RegExp to test against the field
11763 * @param {Boolean} anyMatch True to match any part not just the beginning
11764 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11766 query : function(property, value, anyMatch){
11767 var fn = this.createFilterFn(property, value, anyMatch);
11768 return fn ? this.queryBy(fn) : this.data.clone();
11772 * Query by a function. The specified function will be called with each
11773 * record in this data source. If the function returns true the record is included
11775 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11776 * @param {Object} scope (optional) The scope of the function (defaults to this)
11777 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11779 queryBy : function(fn, scope){
11780 var data = this.snapshot || this.data;
11781 return data.filterBy(fn, scope||this);
11785 * Collects unique values for a particular dataIndex from this store.
11786 * @param {String} dataIndex The property to collect
11787 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11788 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11789 * @return {Array} An array of the unique values
11791 collect : function(dataIndex, allowNull, bypassFilter){
11792 var d = (bypassFilter === true && this.snapshot) ?
11793 this.snapshot.items : this.data.items;
11794 var v, sv, r = [], l = {};
11795 for(var i = 0, len = d.length; i < len; i++){
11796 v = d[i].data[dataIndex];
11798 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11807 * Revert to a view of the Record cache with no filtering applied.
11808 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11810 clearFilter : function(suppressEvent){
11811 if(this.snapshot && this.snapshot != this.data){
11812 this.data = this.snapshot;
11813 delete this.snapshot;
11814 if(suppressEvent !== true){
11815 this.fireEvent("datachanged", this);
11821 afterEdit : function(record){
11822 if(this.modified.indexOf(record) == -1){
11823 this.modified.push(record);
11825 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11829 afterReject : function(record){
11830 this.modified.remove(record);
11831 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11835 afterCommit : function(record){
11836 this.modified.remove(record);
11837 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11841 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11842 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11844 commitChanges : function(){
11845 var m = this.modified.slice(0);
11846 this.modified = [];
11847 for(var i = 0, len = m.length; i < len; i++){
11853 * Cancel outstanding changes on all changed records.
11855 rejectChanges : function(){
11856 var m = this.modified.slice(0);
11857 this.modified = [];
11858 for(var i = 0, len = m.length; i < len; i++){
11863 onMetaChange : function(meta, rtype, o){
11864 this.recordType = rtype;
11865 this.fields = rtype.prototype.fields;
11866 delete this.snapshot;
11867 this.sortInfo = meta.sortInfo || this.sortInfo;
11868 this.modified = [];
11869 this.fireEvent('metachange', this, this.reader.meta);
11872 moveIndex : function(data, type)
11874 var index = this.indexOf(data);
11876 var newIndex = index + type;
11880 this.insert(newIndex, data);
11885 * Ext JS Library 1.1.1
11886 * Copyright(c) 2006-2007, Ext JS, LLC.
11888 * Originally Released Under LGPL - original licence link has changed is not relivant.
11891 * <script type="text/javascript">
11895 * @class Roo.data.SimpleStore
11896 * @extends Roo.data.Store
11897 * Small helper class to make creating Stores from Array data easier.
11898 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11899 * @cfg {Array} fields An array of field definition objects, or field name strings.
11900 * @cfg {Array} data The multi-dimensional array of data
11902 * @param {Object} config
11904 Roo.data.SimpleStore = function(config){
11905 Roo.data.SimpleStore.superclass.constructor.call(this, {
11907 reader: new Roo.data.ArrayReader({
11910 Roo.data.Record.create(config.fields)
11912 proxy : new Roo.data.MemoryProxy(config.data)
11916 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11918 * Ext JS Library 1.1.1
11919 * Copyright(c) 2006-2007, Ext JS, LLC.
11921 * Originally Released Under LGPL - original licence link has changed is not relivant.
11924 * <script type="text/javascript">
11929 * @extends Roo.data.Store
11930 * @class Roo.data.JsonStore
11931 * Small helper class to make creating Stores for JSON data easier. <br/>
11933 var store = new Roo.data.JsonStore({
11934 url: 'get-images.php',
11936 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11939 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11940 * JsonReader and HttpProxy (unless inline data is provided).</b>
11941 * @cfg {Array} fields An array of field definition objects, or field name strings.
11943 * @param {Object} config
11945 Roo.data.JsonStore = function(c){
11946 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11947 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11948 reader: new Roo.data.JsonReader(c, c.fields)
11951 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11953 * Ext JS Library 1.1.1
11954 * Copyright(c) 2006-2007, Ext JS, LLC.
11956 * Originally Released Under LGPL - original licence link has changed is not relivant.
11959 * <script type="text/javascript">
11963 Roo.data.Field = function(config){
11964 if(typeof config == "string"){
11965 config = {name: config};
11967 Roo.apply(this, config);
11970 this.type = "auto";
11973 var st = Roo.data.SortTypes;
11974 // named sortTypes are supported, here we look them up
11975 if(typeof this.sortType == "string"){
11976 this.sortType = st[this.sortType];
11979 // set default sortType for strings and dates
11980 if(!this.sortType){
11983 this.sortType = st.asUCString;
11986 this.sortType = st.asDate;
11989 this.sortType = st.none;
11994 var stripRe = /[\$,%]/g;
11996 // prebuilt conversion function for this field, instead of
11997 // switching every time we're reading a value
11999 var cv, dateFormat = this.dateFormat;
12004 cv = function(v){ return v; };
12007 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12011 return v !== undefined && v !== null && v !== '' ?
12012 parseInt(String(v).replace(stripRe, ""), 10) : '';
12017 return v !== undefined && v !== null && v !== '' ?
12018 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12023 cv = function(v){ return v === true || v === "true" || v == 1; };
12030 if(v instanceof Date){
12034 if(dateFormat == "timestamp"){
12035 return new Date(v*1000);
12037 return Date.parseDate(v, dateFormat);
12039 var parsed = Date.parse(v);
12040 return parsed ? new Date(parsed) : null;
12049 Roo.data.Field.prototype = {
12057 * Ext JS Library 1.1.1
12058 * Copyright(c) 2006-2007, Ext JS, LLC.
12060 * Originally Released Under LGPL - original licence link has changed is not relivant.
12063 * <script type="text/javascript">
12066 // Base class for reading structured data from a data source. This class is intended to be
12067 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12070 * @class Roo.data.DataReader
12071 * Base class for reading structured data from a data source. This class is intended to be
12072 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12075 Roo.data.DataReader = function(meta, recordType){
12079 this.recordType = recordType instanceof Array ?
12080 Roo.data.Record.create(recordType) : recordType;
12083 Roo.data.DataReader.prototype = {
12085 * Create an empty record
12086 * @param {Object} data (optional) - overlay some values
12087 * @return {Roo.data.Record} record created.
12089 newRow : function(d) {
12091 this.recordType.prototype.fields.each(function(c) {
12093 case 'int' : da[c.name] = 0; break;
12094 case 'date' : da[c.name] = new Date(); break;
12095 case 'float' : da[c.name] = 0.0; break;
12096 case 'boolean' : da[c.name] = false; break;
12097 default : da[c.name] = ""; break;
12101 return new this.recordType(Roo.apply(da, d));
12106 * Ext JS Library 1.1.1
12107 * Copyright(c) 2006-2007, Ext JS, LLC.
12109 * Originally Released Under LGPL - original licence link has changed is not relivant.
12112 * <script type="text/javascript">
12116 * @class Roo.data.DataProxy
12117 * @extends Roo.data.Observable
12118 * This class is an abstract base class for implementations which provide retrieval of
12119 * unformatted data objects.<br>
12121 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12122 * (of the appropriate type which knows how to parse the data object) to provide a block of
12123 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12125 * Custom implementations must implement the load method as described in
12126 * {@link Roo.data.HttpProxy#load}.
12128 Roo.data.DataProxy = function(){
12131 * @event beforeload
12132 * Fires before a network request is made to retrieve a data object.
12133 * @param {Object} This DataProxy object.
12134 * @param {Object} params The params parameter to the load function.
12139 * Fires before the load method's callback is called.
12140 * @param {Object} This DataProxy object.
12141 * @param {Object} o The data object.
12142 * @param {Object} arg The callback argument object passed to the load function.
12146 * @event loadexception
12147 * Fires if an Exception occurs during data retrieval.
12148 * @param {Object} This DataProxy object.
12149 * @param {Object} o The data object.
12150 * @param {Object} arg The callback argument object passed to the load function.
12151 * @param {Object} e The Exception.
12153 loadexception : true
12155 Roo.data.DataProxy.superclass.constructor.call(this);
12158 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12161 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12165 * Ext JS Library 1.1.1
12166 * Copyright(c) 2006-2007, Ext JS, LLC.
12168 * Originally Released Under LGPL - original licence link has changed is not relivant.
12171 * <script type="text/javascript">
12174 * @class Roo.data.MemoryProxy
12175 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12176 * to the Reader when its load method is called.
12178 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12180 Roo.data.MemoryProxy = function(data){
12184 Roo.data.MemoryProxy.superclass.constructor.call(this);
12188 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12191 * Load data from the requested source (in this case an in-memory
12192 * data object passed to the constructor), read the data object into
12193 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12194 * process that block using the passed callback.
12195 * @param {Object} params This parameter is not used by the MemoryProxy class.
12196 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12197 * object into a block of Roo.data.Records.
12198 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12199 * The function must be passed <ul>
12200 * <li>The Record block object</li>
12201 * <li>The "arg" argument from the load function</li>
12202 * <li>A boolean success indicator</li>
12204 * @param {Object} scope The scope in which to call the callback
12205 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12207 load : function(params, reader, callback, scope, arg){
12208 params = params || {};
12211 result = reader.readRecords(this.data);
12213 this.fireEvent("loadexception", this, arg, null, e);
12214 callback.call(scope, null, arg, false);
12217 callback.call(scope, result, arg, true);
12221 update : function(params, records){
12226 * Ext JS Library 1.1.1
12227 * Copyright(c) 2006-2007, Ext JS, LLC.
12229 * Originally Released Under LGPL - original licence link has changed is not relivant.
12232 * <script type="text/javascript">
12235 * @class Roo.data.HttpProxy
12236 * @extends Roo.data.DataProxy
12237 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12238 * configured to reference a certain URL.<br><br>
12240 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12241 * from which the running page was served.<br><br>
12243 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12245 * Be aware that to enable the browser to parse an XML document, the server must set
12246 * the Content-Type header in the HTTP response to "text/xml".
12248 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12249 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12250 * will be used to make the request.
12252 Roo.data.HttpProxy = function(conn){
12253 Roo.data.HttpProxy.superclass.constructor.call(this);
12254 // is conn a conn config or a real conn?
12256 this.useAjax = !conn || !conn.events;
12260 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12261 // thse are take from connection...
12264 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12267 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12268 * extra parameters to each request made by this object. (defaults to undefined)
12271 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12272 * to each request made by this object. (defaults to undefined)
12275 * @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)
12278 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12281 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12287 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12291 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12292 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12293 * a finer-grained basis than the DataProxy events.
12295 getConnection : function(){
12296 return this.useAjax ? Roo.Ajax : this.conn;
12300 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12301 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12302 * process that block using the passed callback.
12303 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12304 * for the request to the remote server.
12305 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12306 * object into a block of Roo.data.Records.
12307 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12308 * The function must be passed <ul>
12309 * <li>The Record block object</li>
12310 * <li>The "arg" argument from the load function</li>
12311 * <li>A boolean success indicator</li>
12313 * @param {Object} scope The scope in which to call the callback
12314 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12316 load : function(params, reader, callback, scope, arg){
12317 if(this.fireEvent("beforeload", this, params) !== false){
12319 params : params || {},
12321 callback : callback,
12326 callback : this.loadResponse,
12330 Roo.applyIf(o, this.conn);
12331 if(this.activeRequest){
12332 Roo.Ajax.abort(this.activeRequest);
12334 this.activeRequest = Roo.Ajax.request(o);
12336 this.conn.request(o);
12339 callback.call(scope||this, null, arg, false);
12344 loadResponse : function(o, success, response){
12345 delete this.activeRequest;
12347 this.fireEvent("loadexception", this, o, response);
12348 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12353 result = o.reader.read(response);
12355 this.fireEvent("loadexception", this, o, response, e);
12356 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12360 this.fireEvent("load", this, o, o.request.arg);
12361 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12365 update : function(dataSet){
12370 updateResponse : function(dataSet){
12375 * Ext JS Library 1.1.1
12376 * Copyright(c) 2006-2007, Ext JS, LLC.
12378 * Originally Released Under LGPL - original licence link has changed is not relivant.
12381 * <script type="text/javascript">
12385 * @class Roo.data.ScriptTagProxy
12386 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12387 * other than the originating domain of the running page.<br><br>
12389 * <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
12390 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12392 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12393 * source code that is used as the source inside a <script> tag.<br><br>
12395 * In order for the browser to process the returned data, the server must wrap the data object
12396 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12397 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12398 * depending on whether the callback name was passed:
12401 boolean scriptTag = false;
12402 String cb = request.getParameter("callback");
12405 response.setContentType("text/javascript");
12407 response.setContentType("application/x-json");
12409 Writer out = response.getWriter();
12411 out.write(cb + "(");
12413 out.print(dataBlock.toJsonString());
12420 * @param {Object} config A configuration object.
12422 Roo.data.ScriptTagProxy = function(config){
12423 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12424 Roo.apply(this, config);
12425 this.head = document.getElementsByTagName("head")[0];
12428 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12430 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12432 * @cfg {String} url The URL from which to request the data object.
12435 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12439 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12440 * the server the name of the callback function set up by the load call to process the returned data object.
12441 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12442 * javascript output which calls this named function passing the data object as its only parameter.
12444 callbackParam : "callback",
12446 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12447 * name to the request.
12452 * Load data from the configured URL, read the data object into
12453 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12454 * process that block using the passed callback.
12455 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12456 * for the request to the remote server.
12457 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12458 * object into a block of Roo.data.Records.
12459 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12460 * The function must be passed <ul>
12461 * <li>The Record block object</li>
12462 * <li>The "arg" argument from the load function</li>
12463 * <li>A boolean success indicator</li>
12465 * @param {Object} scope The scope in which to call the callback
12466 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12468 load : function(params, reader, callback, scope, arg){
12469 if(this.fireEvent("beforeload", this, params) !== false){
12471 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12473 var url = this.url;
12474 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12476 url += "&_dc=" + (new Date().getTime());
12478 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12481 cb : "stcCallback"+transId,
12482 scriptId : "stcScript"+transId,
12486 callback : callback,
12492 window[trans.cb] = function(o){
12493 conn.handleResponse(o, trans);
12496 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12498 if(this.autoAbort !== false){
12502 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12504 var script = document.createElement("script");
12505 script.setAttribute("src", url);
12506 script.setAttribute("type", "text/javascript");
12507 script.setAttribute("id", trans.scriptId);
12508 this.head.appendChild(script);
12510 this.trans = trans;
12512 callback.call(scope||this, null, arg, false);
12517 isLoading : function(){
12518 return this.trans ? true : false;
12522 * Abort the current server request.
12524 abort : function(){
12525 if(this.isLoading()){
12526 this.destroyTrans(this.trans);
12531 destroyTrans : function(trans, isLoaded){
12532 this.head.removeChild(document.getElementById(trans.scriptId));
12533 clearTimeout(trans.timeoutId);
12535 window[trans.cb] = undefined;
12537 delete window[trans.cb];
12540 // if hasn't been loaded, wait for load to remove it to prevent script error
12541 window[trans.cb] = function(){
12542 window[trans.cb] = undefined;
12544 delete window[trans.cb];
12551 handleResponse : function(o, trans){
12552 this.trans = false;
12553 this.destroyTrans(trans, true);
12556 result = trans.reader.readRecords(o);
12558 this.fireEvent("loadexception", this, o, trans.arg, e);
12559 trans.callback.call(trans.scope||window, null, trans.arg, false);
12562 this.fireEvent("load", this, o, trans.arg);
12563 trans.callback.call(trans.scope||window, result, trans.arg, true);
12567 handleFailure : function(trans){
12568 this.trans = false;
12569 this.destroyTrans(trans, false);
12570 this.fireEvent("loadexception", this, null, trans.arg);
12571 trans.callback.call(trans.scope||window, null, trans.arg, false);
12575 * Ext JS Library 1.1.1
12576 * Copyright(c) 2006-2007, Ext JS, LLC.
12578 * Originally Released Under LGPL - original licence link has changed is not relivant.
12581 * <script type="text/javascript">
12585 * @class Roo.data.JsonReader
12586 * @extends Roo.data.DataReader
12587 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12588 * based on mappings in a provided Roo.data.Record constructor.
12590 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12591 * in the reply previously.
12596 var RecordDef = Roo.data.Record.create([
12597 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12598 {name: 'occupation'} // This field will use "occupation" as the mapping.
12600 var myReader = new Roo.data.JsonReader({
12601 totalProperty: "results", // The property which contains the total dataset size (optional)
12602 root: "rows", // The property which contains an Array of row objects
12603 id: "id" // The property within each row object that provides an ID for the record (optional)
12607 * This would consume a JSON file like this:
12609 { 'results': 2, 'rows': [
12610 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12611 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12614 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12615 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12616 * paged from the remote server.
12617 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12618 * @cfg {String} root name of the property which contains the Array of row objects.
12619 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12620 * @cfg {Array} fields Array of field definition objects
12622 * Create a new JsonReader
12623 * @param {Object} meta Metadata configuration options
12624 * @param {Object} recordType Either an Array of field definition objects,
12625 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12627 Roo.data.JsonReader = function(meta, recordType){
12630 // set some defaults:
12631 Roo.applyIf(meta, {
12632 totalProperty: 'total',
12633 successProperty : 'success',
12638 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12640 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12643 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12644 * Used by Store query builder to append _requestMeta to params.
12647 metaFromRemote : false,
12649 * This method is only used by a DataProxy which has retrieved data from a remote server.
12650 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12651 * @return {Object} data A data block which is used by an Roo.data.Store object as
12652 * a cache of Roo.data.Records.
12654 read : function(response){
12655 var json = response.responseText;
12657 var o = /* eval:var:o */ eval("("+json+")");
12659 throw {message: "JsonReader.read: Json object not found"};
12665 this.metaFromRemote = true;
12666 this.meta = o.metaData;
12667 this.recordType = Roo.data.Record.create(o.metaData.fields);
12668 this.onMetaChange(this.meta, this.recordType, o);
12670 return this.readRecords(o);
12673 // private function a store will implement
12674 onMetaChange : function(meta, recordType, o){
12681 simpleAccess: function(obj, subsc) {
12688 getJsonAccessor: function(){
12690 return function(expr) {
12692 return(re.test(expr))
12693 ? new Function("obj", "return obj." + expr)
12698 return Roo.emptyFn;
12703 * Create a data block containing Roo.data.Records from an XML document.
12704 * @param {Object} o An object which contains an Array of row objects in the property specified
12705 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12706 * which contains the total size of the dataset.
12707 * @return {Object} data A data block which is used by an Roo.data.Store object as
12708 * a cache of Roo.data.Records.
12710 readRecords : function(o){
12712 * After any data loads, the raw JSON data is available for further custom processing.
12716 var s = this.meta, Record = this.recordType,
12717 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12719 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12721 if(s.totalProperty) {
12722 this.getTotal = this.getJsonAccessor(s.totalProperty);
12724 if(s.successProperty) {
12725 this.getSuccess = this.getJsonAccessor(s.successProperty);
12727 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12729 var g = this.getJsonAccessor(s.id);
12730 this.getId = function(rec) {
12732 return (r === undefined || r === "") ? null : r;
12735 this.getId = function(){return null;};
12738 for(var jj = 0; jj < fl; jj++){
12740 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12741 this.ef[jj] = this.getJsonAccessor(map);
12745 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12746 if(s.totalProperty){
12747 var vt = parseInt(this.getTotal(o), 10);
12752 if(s.successProperty){
12753 var vs = this.getSuccess(o);
12754 if(vs === false || vs === 'false'){
12759 for(var i = 0; i < c; i++){
12762 var id = this.getId(n);
12763 for(var j = 0; j < fl; j++){
12765 var v = this.ef[j](n);
12767 Roo.log('missing convert for ' + f.name);
12771 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12773 var record = new Record(values, id);
12775 records[i] = record;
12781 totalRecords : totalRecords
12786 * Ext JS Library 1.1.1
12787 * Copyright(c) 2006-2007, Ext JS, LLC.
12789 * Originally Released Under LGPL - original licence link has changed is not relivant.
12792 * <script type="text/javascript">
12796 * @class Roo.data.ArrayReader
12797 * @extends Roo.data.DataReader
12798 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12799 * Each element of that Array represents a row of data fields. The
12800 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12801 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12805 var RecordDef = Roo.data.Record.create([
12806 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12807 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12809 var myReader = new Roo.data.ArrayReader({
12810 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12814 * This would consume an Array like this:
12816 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12818 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12820 * Create a new JsonReader
12821 * @param {Object} meta Metadata configuration options.
12822 * @param {Object} recordType Either an Array of field definition objects
12823 * as specified to {@link Roo.data.Record#create},
12824 * or an {@link Roo.data.Record} object
12825 * created using {@link Roo.data.Record#create}.
12827 Roo.data.ArrayReader = function(meta, recordType){
12828 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12831 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12833 * Create a data block containing Roo.data.Records from an XML document.
12834 * @param {Object} o An Array of row objects which represents the dataset.
12835 * @return {Object} data A data block which is used by an Roo.data.Store object as
12836 * a cache of Roo.data.Records.
12838 readRecords : function(o){
12839 var sid = this.meta ? this.meta.id : null;
12840 var recordType = this.recordType, fields = recordType.prototype.fields;
12843 for(var i = 0; i < root.length; i++){
12846 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12847 for(var j = 0, jlen = fields.length; j < jlen; j++){
12848 var f = fields.items[j];
12849 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12850 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12852 values[f.name] = v;
12854 var record = new recordType(values, id);
12856 records[records.length] = record;
12860 totalRecords : records.length
12869 * @class Roo.bootstrap.ComboBox
12870 * @extends Roo.bootstrap.TriggerField
12871 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12872 * @cfg {Boolean} append (true|false) default false
12873 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12874 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12875 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12876 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12877 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12878 * @cfg {Boolean} animate default true
12879 * @cfg {Boolean} emptyResultText only for touch device
12880 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12881 * @cfg {String} emptyTitle default ''
12883 * Create a new ComboBox.
12884 * @param {Object} config Configuration options
12886 Roo.bootstrap.ComboBox = function(config){
12887 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12891 * Fires when the dropdown list is expanded
12892 * @param {Roo.bootstrap.ComboBox} combo This combo box
12897 * Fires when the dropdown list is collapsed
12898 * @param {Roo.bootstrap.ComboBox} combo This combo box
12902 * @event beforeselect
12903 * Fires before a list item is selected. Return false to cancel the selection.
12904 * @param {Roo.bootstrap.ComboBox} combo This combo box
12905 * @param {Roo.data.Record} record The data record returned from the underlying store
12906 * @param {Number} index The index of the selected item in the dropdown list
12908 'beforeselect' : true,
12911 * Fires when a list item is selected
12912 * @param {Roo.bootstrap.ComboBox} combo This combo box
12913 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12914 * @param {Number} index The index of the selected item in the dropdown list
12918 * @event beforequery
12919 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12920 * The event object passed has these properties:
12921 * @param {Roo.bootstrap.ComboBox} combo This combo box
12922 * @param {String} query The query
12923 * @param {Boolean} forceAll true to force "all" query
12924 * @param {Boolean} cancel true to cancel the query
12925 * @param {Object} e The query event object
12927 'beforequery': true,
12930 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12931 * @param {Roo.bootstrap.ComboBox} combo This combo box
12936 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12937 * @param {Roo.bootstrap.ComboBox} combo This combo box
12938 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12943 * Fires when the remove value from the combobox array
12944 * @param {Roo.bootstrap.ComboBox} combo This combo box
12948 * @event afterremove
12949 * Fires when the remove value from the combobox array
12950 * @param {Roo.bootstrap.ComboBox} combo This combo box
12952 'afterremove' : true,
12954 * @event specialfilter
12955 * Fires when specialfilter
12956 * @param {Roo.bootstrap.ComboBox} combo This combo box
12958 'specialfilter' : true,
12961 * Fires when tick the element
12962 * @param {Roo.bootstrap.ComboBox} combo This combo box
12966 * @event touchviewdisplay
12967 * Fires when touch view require special display (default is using displayField)
12968 * @param {Roo.bootstrap.ComboBox} combo This combo box
12969 * @param {Object} cfg set html .
12971 'touchviewdisplay' : true
12976 this.tickItems = [];
12978 this.selectedIndex = -1;
12979 if(this.mode == 'local'){
12980 if(config.queryDelay === undefined){
12981 this.queryDelay = 10;
12983 if(config.minChars === undefined){
12989 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12992 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12993 * rendering into an Roo.Editor, defaults to false)
12996 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12997 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13000 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13003 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13004 * the dropdown list (defaults to undefined, with no header element)
13008 * @cfg {String/Roo.Template} tpl The template to use to render the output
13012 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13014 listWidth: undefined,
13016 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13017 * mode = 'remote' or 'text' if mode = 'local')
13019 displayField: undefined,
13022 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13023 * mode = 'remote' or 'value' if mode = 'local').
13024 * Note: use of a valueField requires the user make a selection
13025 * in order for a value to be mapped.
13027 valueField: undefined,
13029 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13034 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13035 * field's data value (defaults to the underlying DOM element's name)
13037 hiddenName: undefined,
13039 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13043 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13045 selectedClass: 'active',
13048 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13052 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13053 * anchor positions (defaults to 'tl-bl')
13055 listAlign: 'tl-bl?',
13057 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13061 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13062 * query specified by the allQuery config option (defaults to 'query')
13064 triggerAction: 'query',
13066 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13067 * (defaults to 4, does not apply if editable = false)
13071 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13072 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13076 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13077 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13081 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13082 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13086 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13087 * when editable = true (defaults to false)
13089 selectOnFocus:false,
13091 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13093 queryParam: 'query',
13095 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13096 * when mode = 'remote' (defaults to 'Loading...')
13098 loadingText: 'Loading...',
13100 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13104 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13108 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13109 * traditional select (defaults to true)
13113 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13117 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13121 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13122 * listWidth has a higher value)
13126 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13127 * allow the user to set arbitrary text into the field (defaults to false)
13129 forceSelection:false,
13131 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13132 * if typeAhead = true (defaults to 250)
13134 typeAheadDelay : 250,
13136 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13137 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13139 valueNotFoundText : undefined,
13141 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13143 blockFocus : false,
13146 * @cfg {Boolean} disableClear Disable showing of clear button.
13148 disableClear : false,
13150 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13152 alwaysQuery : false,
13155 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13160 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13162 invalidClass : "has-warning",
13165 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13167 validClass : "has-success",
13170 * @cfg {Boolean} specialFilter (true|false) special filter default false
13172 specialFilter : false,
13175 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13177 mobileTouchView : true,
13180 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13182 useNativeIOS : false,
13185 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13187 mobile_restrict_height : false,
13189 ios_options : false,
13201 btnPosition : 'right',
13202 triggerList : true,
13203 showToggleBtn : true,
13205 emptyResultText: 'Empty',
13206 triggerText : 'Select',
13209 // element that contains real text value.. (when hidden is used..)
13211 getAutoCreate : function()
13216 * Render classic select for iso
13219 if(Roo.isIOS && this.useNativeIOS){
13220 cfg = this.getAutoCreateNativeIOS();
13228 if(Roo.isTouch && this.mobileTouchView){
13229 cfg = this.getAutoCreateTouchView();
13236 if(!this.tickable){
13237 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13242 * ComboBox with tickable selections
13245 var align = this.labelAlign || this.parentLabelAlign();
13248 cls : 'form-group roo-combobox-tickable' //input-group
13251 var btn_text_select = '';
13252 var btn_text_done = '';
13253 var btn_text_cancel = '';
13255 if (this.btn_text_show) {
13256 btn_text_select = 'Select';
13257 btn_text_done = 'Done';
13258 btn_text_cancel = 'Cancel';
13263 cls : 'tickable-buttons',
13268 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13269 //html : this.triggerText
13270 html: btn_text_select
13276 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13278 html: btn_text_done
13284 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13286 html: btn_text_cancel
13292 buttons.cn.unshift({
13294 cls: 'roo-select2-search-field-input'
13300 Roo.each(buttons.cn, function(c){
13302 c.cls += ' btn-' + _this.size;
13305 if (_this.disabled) {
13316 cls: 'form-hidden-field'
13320 cls: 'roo-select2-choices',
13324 cls: 'roo-select2-search-field',
13335 cls: 'roo-select2-container input-group roo-select2-container-multi',
13341 // cls: 'typeahead typeahead-long dropdown-menu',
13342 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13347 if(this.hasFeedback && !this.allowBlank){
13351 cls: 'glyphicon form-control-feedback'
13354 combobox.cn.push(feedback);
13359 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13360 tooltip : 'This field is required'
13362 if (Roo.bootstrap.version == 4) {
13365 style : 'display:none'
13368 if (align ==='left' && this.fieldLabel.length) {
13370 cfg.cls += ' roo-form-group-label-left row';
13377 cls : 'control-label col-form-label',
13378 html : this.fieldLabel
13390 var labelCfg = cfg.cn[1];
13391 var contentCfg = cfg.cn[2];
13394 if(this.indicatorpos == 'right'){
13400 cls : 'control-label col-form-label',
13404 html : this.fieldLabel
13420 labelCfg = cfg.cn[0];
13421 contentCfg = cfg.cn[1];
13425 if(this.labelWidth > 12){
13426 labelCfg.style = "width: " + this.labelWidth + 'px';
13429 if(this.labelWidth < 13 && this.labelmd == 0){
13430 this.labelmd = this.labelWidth;
13433 if(this.labellg > 0){
13434 labelCfg.cls += ' col-lg-' + this.labellg;
13435 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13438 if(this.labelmd > 0){
13439 labelCfg.cls += ' col-md-' + this.labelmd;
13440 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13443 if(this.labelsm > 0){
13444 labelCfg.cls += ' col-sm-' + this.labelsm;
13445 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13448 if(this.labelxs > 0){
13449 labelCfg.cls += ' col-xs-' + this.labelxs;
13450 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13454 } else if ( this.fieldLabel.length) {
13455 // Roo.log(" label");
13460 //cls : 'input-group-addon',
13461 html : this.fieldLabel
13466 if(this.indicatorpos == 'right'){
13470 //cls : 'input-group-addon',
13471 html : this.fieldLabel
13481 // Roo.log(" no label && no align");
13488 ['xs','sm','md','lg'].map(function(size){
13489 if (settings[size]) {
13490 cfg.cls += ' col-' + size + '-' + settings[size];
13498 _initEventsCalled : false,
13501 initEvents: function()
13503 if (this._initEventsCalled) { // as we call render... prevent looping...
13506 this._initEventsCalled = true;
13509 throw "can not find store for combo";
13512 this.indicator = this.indicatorEl();
13514 this.store = Roo.factory(this.store, Roo.data);
13515 this.store.parent = this;
13517 // if we are building from html. then this element is so complex, that we can not really
13518 // use the rendered HTML.
13519 // so we have to trash and replace the previous code.
13520 if (Roo.XComponent.build_from_html) {
13521 // remove this element....
13522 var e = this.el.dom, k=0;
13523 while (e ) { e = e.previousSibling; ++k;}
13528 this.rendered = false;
13530 this.render(this.parent().getChildContainer(true), k);
13533 if(Roo.isIOS && this.useNativeIOS){
13534 this.initIOSView();
13542 if(Roo.isTouch && this.mobileTouchView){
13543 this.initTouchView();
13548 this.initTickableEvents();
13552 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13554 if(this.hiddenName){
13556 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13558 this.hiddenField.dom.value =
13559 this.hiddenValue !== undefined ? this.hiddenValue :
13560 this.value !== undefined ? this.value : '';
13562 // prevent input submission
13563 this.el.dom.removeAttribute('name');
13564 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13569 // this.el.dom.setAttribute('autocomplete', 'off');
13572 var cls = 'x-combo-list';
13574 //this.list = new Roo.Layer({
13575 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13581 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13582 _this.list.setWidth(lw);
13585 this.list.on('mouseover', this.onViewOver, this);
13586 this.list.on('mousemove', this.onViewMove, this);
13587 this.list.on('scroll', this.onViewScroll, this);
13590 this.list.swallowEvent('mousewheel');
13591 this.assetHeight = 0;
13594 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13595 this.assetHeight += this.header.getHeight();
13598 this.innerList = this.list.createChild({cls:cls+'-inner'});
13599 this.innerList.on('mouseover', this.onViewOver, this);
13600 this.innerList.on('mousemove', this.onViewMove, this);
13601 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13603 if(this.allowBlank && !this.pageSize && !this.disableClear){
13604 this.footer = this.list.createChild({cls:cls+'-ft'});
13605 this.pageTb = new Roo.Toolbar(this.footer);
13609 this.footer = this.list.createChild({cls:cls+'-ft'});
13610 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13611 {pageSize: this.pageSize});
13615 if (this.pageTb && this.allowBlank && !this.disableClear) {
13617 this.pageTb.add(new Roo.Toolbar.Fill(), {
13618 cls: 'x-btn-icon x-btn-clear',
13620 handler: function()
13623 _this.clearValue();
13624 _this.onSelect(false, -1);
13629 this.assetHeight += this.footer.getHeight();
13634 this.tpl = '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13637 this.view = new Roo.View(this.list, this.tpl, {
13638 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13640 //this.view.wrapEl.setDisplayed(false);
13641 this.view.on('click', this.onViewClick, this);
13644 this.store.on('beforeload', this.onBeforeLoad, this);
13645 this.store.on('load', this.onLoad, this);
13646 this.store.on('loadexception', this.onLoadException, this);
13648 if(this.resizable){
13649 this.resizer = new Roo.Resizable(this.list, {
13650 pinned:true, handles:'se'
13652 this.resizer.on('resize', function(r, w, h){
13653 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13654 this.listWidth = w;
13655 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13656 this.restrictHeight();
13658 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13661 if(!this.editable){
13662 this.editable = true;
13663 this.setEditable(false);
13668 if (typeof(this.events.add.listeners) != 'undefined') {
13670 this.addicon = this.wrap.createChild(
13671 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13673 this.addicon.on('click', function(e) {
13674 this.fireEvent('add', this);
13677 if (typeof(this.events.edit.listeners) != 'undefined') {
13679 this.editicon = this.wrap.createChild(
13680 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13681 if (this.addicon) {
13682 this.editicon.setStyle('margin-left', '40px');
13684 this.editicon.on('click', function(e) {
13686 // we fire even if inothing is selected..
13687 this.fireEvent('edit', this, this.lastData );
13693 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13694 "up" : function(e){
13695 this.inKeyMode = true;
13699 "down" : function(e){
13700 if(!this.isExpanded()){
13701 this.onTriggerClick();
13703 this.inKeyMode = true;
13708 "enter" : function(e){
13709 // this.onViewClick();
13713 if(this.fireEvent("specialkey", this, e)){
13714 this.onViewClick(false);
13720 "esc" : function(e){
13724 "tab" : function(e){
13727 if(this.fireEvent("specialkey", this, e)){
13728 this.onViewClick(false);
13736 doRelay : function(foo, bar, hname){
13737 if(hname == 'down' || this.scope.isExpanded()){
13738 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13747 this.queryDelay = Math.max(this.queryDelay || 10,
13748 this.mode == 'local' ? 10 : 250);
13751 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13753 if(this.typeAhead){
13754 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13756 if(this.editable !== false){
13757 this.inputEl().on("keyup", this.onKeyUp, this);
13759 if(this.forceSelection){
13760 this.inputEl().on('blur', this.doForce, this);
13764 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13765 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13769 initTickableEvents: function()
13773 if(this.hiddenName){
13775 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13777 this.hiddenField.dom.value =
13778 this.hiddenValue !== undefined ? this.hiddenValue :
13779 this.value !== undefined ? this.value : '';
13781 // prevent input submission
13782 this.el.dom.removeAttribute('name');
13783 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13788 // this.list = this.el.select('ul.dropdown-menu',true).first();
13790 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13791 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13792 if(this.triggerList){
13793 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13796 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13797 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13799 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13800 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13802 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13803 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13805 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13806 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13807 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13810 this.cancelBtn.hide();
13815 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13816 _this.list.setWidth(lw);
13819 this.list.on('mouseover', this.onViewOver, this);
13820 this.list.on('mousemove', this.onViewMove, this);
13822 this.list.on('scroll', this.onViewScroll, this);
13825 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13826 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13829 this.view = new Roo.View(this.list, this.tpl, {
13834 selectedClass: this.selectedClass
13837 //this.view.wrapEl.setDisplayed(false);
13838 this.view.on('click', this.onViewClick, this);
13842 this.store.on('beforeload', this.onBeforeLoad, this);
13843 this.store.on('load', this.onLoad, this);
13844 this.store.on('loadexception', this.onLoadException, this);
13847 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13848 "up" : function(e){
13849 this.inKeyMode = true;
13853 "down" : function(e){
13854 this.inKeyMode = true;
13858 "enter" : function(e){
13859 if(this.fireEvent("specialkey", this, e)){
13860 this.onViewClick(false);
13866 "esc" : function(e){
13867 this.onTickableFooterButtonClick(e, false, false);
13870 "tab" : function(e){
13871 this.fireEvent("specialkey", this, e);
13873 this.onTickableFooterButtonClick(e, false, false);
13880 doRelay : function(e, fn, key){
13881 if(this.scope.isExpanded()){
13882 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13891 this.queryDelay = Math.max(this.queryDelay || 10,
13892 this.mode == 'local' ? 10 : 250);
13895 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13897 if(this.typeAhead){
13898 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13901 if(this.editable !== false){
13902 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13905 this.indicator = this.indicatorEl();
13907 if(this.indicator){
13908 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13909 this.indicator.hide();
13914 onDestroy : function(){
13916 this.view.setStore(null);
13917 this.view.el.removeAllListeners();
13918 this.view.el.remove();
13919 this.view.purgeListeners();
13922 this.list.dom.innerHTML = '';
13926 this.store.un('beforeload', this.onBeforeLoad, this);
13927 this.store.un('load', this.onLoad, this);
13928 this.store.un('loadexception', this.onLoadException, this);
13930 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13934 fireKey : function(e){
13935 if(e.isNavKeyPress() && !this.list.isVisible()){
13936 this.fireEvent("specialkey", this, e);
13941 onResize: function(w, h){
13942 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13944 // if(typeof w != 'number'){
13945 // // we do not handle it!?!?
13948 // var tw = this.trigger.getWidth();
13949 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13950 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13952 // this.inputEl().setWidth( this.adjustWidth('input', x));
13954 // //this.trigger.setStyle('left', x+'px');
13956 // if(this.list && this.listWidth === undefined){
13957 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13958 // this.list.setWidth(lw);
13959 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13967 * Allow or prevent the user from directly editing the field text. If false is passed,
13968 * the user will only be able to select from the items defined in the dropdown list. This method
13969 * is the runtime equivalent of setting the 'editable' config option at config time.
13970 * @param {Boolean} value True to allow the user to directly edit the field text
13972 setEditable : function(value){
13973 if(value == this.editable){
13976 this.editable = value;
13978 this.inputEl().dom.setAttribute('readOnly', true);
13979 this.inputEl().on('mousedown', this.onTriggerClick, this);
13980 this.inputEl().addClass('x-combo-noedit');
13982 this.inputEl().dom.setAttribute('readOnly', false);
13983 this.inputEl().un('mousedown', this.onTriggerClick, this);
13984 this.inputEl().removeClass('x-combo-noedit');
13990 onBeforeLoad : function(combo,opts){
13991 if(!this.hasFocus){
13995 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13997 this.restrictHeight();
13998 this.selectedIndex = -1;
14002 onLoad : function(){
14004 this.hasQuery = false;
14006 if(!this.hasFocus){
14010 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14011 this.loading.hide();
14014 if(this.store.getCount() > 0){
14017 this.restrictHeight();
14018 if(this.lastQuery == this.allQuery){
14019 if(this.editable && !this.tickable){
14020 this.inputEl().dom.select();
14024 !this.selectByValue(this.value, true) &&
14027 !this.store.lastOptions ||
14028 typeof(this.store.lastOptions.add) == 'undefined' ||
14029 this.store.lastOptions.add != true
14032 this.select(0, true);
14035 if(this.autoFocus){
14038 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14039 this.taTask.delay(this.typeAheadDelay);
14043 this.onEmptyResults();
14049 onLoadException : function()
14051 this.hasQuery = false;
14053 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14054 this.loading.hide();
14057 if(this.tickable && this.editable){
14062 // only causes errors at present
14063 //Roo.log(this.store.reader.jsonData);
14064 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14066 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14072 onTypeAhead : function(){
14073 if(this.store.getCount() > 0){
14074 var r = this.store.getAt(0);
14075 var newValue = r.data[this.displayField];
14076 var len = newValue.length;
14077 var selStart = this.getRawValue().length;
14079 if(selStart != len){
14080 this.setRawValue(newValue);
14081 this.selectText(selStart, newValue.length);
14087 onSelect : function(record, index){
14089 if(this.fireEvent('beforeselect', this, record, index) !== false){
14091 this.setFromData(index > -1 ? record.data : false);
14094 this.fireEvent('select', this, record, index);
14099 * Returns the currently selected field value or empty string if no value is set.
14100 * @return {String} value The selected value
14102 getValue : function()
14104 if(Roo.isIOS && this.useNativeIOS){
14105 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14109 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14112 if(this.valueField){
14113 return typeof this.value != 'undefined' ? this.value : '';
14115 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14119 getRawValue : function()
14121 if(Roo.isIOS && this.useNativeIOS){
14122 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14125 var v = this.inputEl().getValue();
14131 * Clears any text/value currently set in the field
14133 clearValue : function(){
14135 if(this.hiddenField){
14136 this.hiddenField.dom.value = '';
14139 this.setRawValue('');
14140 this.lastSelectionText = '';
14141 this.lastData = false;
14143 var close = this.closeTriggerEl();
14154 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14155 * will be displayed in the field. If the value does not match the data value of an existing item,
14156 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14157 * Otherwise the field will be blank (although the value will still be set).
14158 * @param {String} value The value to match
14160 setValue : function(v)
14162 if(Roo.isIOS && this.useNativeIOS){
14163 this.setIOSValue(v);
14173 if(this.valueField){
14174 var r = this.findRecord(this.valueField, v);
14176 text = r.data[this.displayField];
14177 }else if(this.valueNotFoundText !== undefined){
14178 text = this.valueNotFoundText;
14181 this.lastSelectionText = text;
14182 if(this.hiddenField){
14183 this.hiddenField.dom.value = v;
14185 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14188 var close = this.closeTriggerEl();
14191 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14197 * @property {Object} the last set data for the element
14202 * Sets the value of the field based on a object which is related to the record format for the store.
14203 * @param {Object} value the value to set as. or false on reset?
14205 setFromData : function(o){
14212 var dv = ''; // display value
14213 var vv = ''; // value value..
14215 if (this.displayField) {
14216 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14218 // this is an error condition!!!
14219 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14222 if(this.valueField){
14223 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14226 var close = this.closeTriggerEl();
14229 if(dv.length || vv * 1 > 0){
14231 this.blockFocus=true;
14237 if(this.hiddenField){
14238 this.hiddenField.dom.value = vv;
14240 this.lastSelectionText = dv;
14241 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14245 // no hidden field.. - we store the value in 'value', but still display
14246 // display field!!!!
14247 this.lastSelectionText = dv;
14248 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14255 reset : function(){
14256 // overridden so that last data is reset..
14263 this.setValue(this.originalValue);
14264 //this.clearInvalid();
14265 this.lastData = false;
14267 this.view.clearSelections();
14273 findRecord : function(prop, value){
14275 if(this.store.getCount() > 0){
14276 this.store.each(function(r){
14277 if(r.data[prop] == value){
14287 getName: function()
14289 // returns hidden if it's set..
14290 if (!this.rendered) {return ''};
14291 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14295 onViewMove : function(e, t){
14296 this.inKeyMode = false;
14300 onViewOver : function(e, t){
14301 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14304 var item = this.view.findItemFromChild(t);
14307 var index = this.view.indexOf(item);
14308 this.select(index, false);
14313 onViewClick : function(view, doFocus, el, e)
14315 var index = this.view.getSelectedIndexes()[0];
14317 var r = this.store.getAt(index);
14321 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14328 Roo.each(this.tickItems, function(v,k){
14330 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14332 _this.tickItems.splice(k, 1);
14334 if(typeof(e) == 'undefined' && view == false){
14335 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14347 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14348 this.tickItems.push(r.data);
14351 if(typeof(e) == 'undefined' && view == false){
14352 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14359 this.onSelect(r, index);
14361 if(doFocus !== false && !this.blockFocus){
14362 this.inputEl().focus();
14367 restrictHeight : function(){
14368 //this.innerList.dom.style.height = '';
14369 //var inner = this.innerList.dom;
14370 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14371 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14372 //this.list.beginUpdate();
14373 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14374 this.list.alignTo(this.inputEl(), this.listAlign);
14375 this.list.alignTo(this.inputEl(), this.listAlign);
14376 //this.list.endUpdate();
14380 onEmptyResults : function(){
14382 if(this.tickable && this.editable){
14383 this.hasFocus = false;
14384 this.restrictHeight();
14392 * Returns true if the dropdown list is expanded, else false.
14394 isExpanded : function(){
14395 return this.list.isVisible();
14399 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14400 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14401 * @param {String} value The data value of the item to select
14402 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14403 * selected item if it is not currently in view (defaults to true)
14404 * @return {Boolean} True if the value matched an item in the list, else false
14406 selectByValue : function(v, scrollIntoView){
14407 if(v !== undefined && v !== null){
14408 var r = this.findRecord(this.valueField || this.displayField, v);
14410 this.select(this.store.indexOf(r), scrollIntoView);
14418 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14419 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14420 * @param {Number} index The zero-based index of the list item to select
14421 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14422 * selected item if it is not currently in view (defaults to true)
14424 select : function(index, scrollIntoView){
14425 this.selectedIndex = index;
14426 this.view.select(index);
14427 if(scrollIntoView !== false){
14428 var el = this.view.getNode(index);
14430 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14433 this.list.scrollChildIntoView(el, false);
14439 selectNext : function(){
14440 var ct = this.store.getCount();
14442 if(this.selectedIndex == -1){
14444 }else if(this.selectedIndex < ct-1){
14445 this.select(this.selectedIndex+1);
14451 selectPrev : function(){
14452 var ct = this.store.getCount();
14454 if(this.selectedIndex == -1){
14456 }else if(this.selectedIndex != 0){
14457 this.select(this.selectedIndex-1);
14463 onKeyUp : function(e){
14464 if(this.editable !== false && !e.isSpecialKey()){
14465 this.lastKey = e.getKey();
14466 this.dqTask.delay(this.queryDelay);
14471 validateBlur : function(){
14472 return !this.list || !this.list.isVisible();
14476 initQuery : function(){
14478 var v = this.getRawValue();
14480 if(this.tickable && this.editable){
14481 v = this.tickableInputEl().getValue();
14488 doForce : function(){
14489 if(this.inputEl().dom.value.length > 0){
14490 this.inputEl().dom.value =
14491 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14497 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14498 * query allowing the query action to be canceled if needed.
14499 * @param {String} query The SQL query to execute
14500 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14501 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14502 * saved in the current store (defaults to false)
14504 doQuery : function(q, forceAll){
14506 if(q === undefined || q === null){
14511 forceAll: forceAll,
14515 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14520 forceAll = qe.forceAll;
14521 if(forceAll === true || (q.length >= this.minChars)){
14523 this.hasQuery = true;
14525 if(this.lastQuery != q || this.alwaysQuery){
14526 this.lastQuery = q;
14527 if(this.mode == 'local'){
14528 this.selectedIndex = -1;
14530 this.store.clearFilter();
14533 if(this.specialFilter){
14534 this.fireEvent('specialfilter', this);
14539 this.store.filter(this.displayField, q);
14542 this.store.fireEvent("datachanged", this.store);
14549 this.store.baseParams[this.queryParam] = q;
14551 var options = {params : this.getParams(q)};
14554 options.add = true;
14555 options.params.start = this.page * this.pageSize;
14558 this.store.load(options);
14561 * this code will make the page width larger, at the beginning, the list not align correctly,
14562 * we should expand the list on onLoad
14563 * so command out it
14568 this.selectedIndex = -1;
14573 this.loadNext = false;
14577 getParams : function(q){
14579 //p[this.queryParam] = q;
14583 p.limit = this.pageSize;
14589 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14591 collapse : function(){
14592 if(!this.isExpanded()){
14598 this.hasFocus = false;
14602 this.cancelBtn.hide();
14603 this.trigger.show();
14606 this.tickableInputEl().dom.value = '';
14607 this.tickableInputEl().blur();
14612 Roo.get(document).un('mousedown', this.collapseIf, this);
14613 Roo.get(document).un('mousewheel', this.collapseIf, this);
14614 if (!this.editable) {
14615 Roo.get(document).un('keydown', this.listKeyPress, this);
14617 this.fireEvent('collapse', this);
14623 collapseIf : function(e){
14624 var in_combo = e.within(this.el);
14625 var in_list = e.within(this.list);
14626 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14628 if (in_combo || in_list || is_list) {
14629 //e.stopPropagation();
14634 this.onTickableFooterButtonClick(e, false, false);
14642 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14644 expand : function(){
14646 if(this.isExpanded() || !this.hasFocus){
14650 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14651 this.list.setWidth(lw);
14657 this.restrictHeight();
14661 this.tickItems = Roo.apply([], this.item);
14664 this.cancelBtn.show();
14665 this.trigger.hide();
14668 this.tickableInputEl().focus();
14673 Roo.get(document).on('mousedown', this.collapseIf, this);
14674 Roo.get(document).on('mousewheel', this.collapseIf, this);
14675 if (!this.editable) {
14676 Roo.get(document).on('keydown', this.listKeyPress, this);
14679 this.fireEvent('expand', this);
14683 // Implements the default empty TriggerField.onTriggerClick function
14684 onTriggerClick : function(e)
14686 Roo.log('trigger click');
14688 if(this.disabled || !this.triggerList){
14693 this.loadNext = false;
14695 if(this.isExpanded()){
14697 if (!this.blockFocus) {
14698 this.inputEl().focus();
14702 this.hasFocus = true;
14703 if(this.triggerAction == 'all') {
14704 this.doQuery(this.allQuery, true);
14706 this.doQuery(this.getRawValue());
14708 if (!this.blockFocus) {
14709 this.inputEl().focus();
14714 onTickableTriggerClick : function(e)
14721 this.loadNext = false;
14722 this.hasFocus = true;
14724 if(this.triggerAction == 'all') {
14725 this.doQuery(this.allQuery, true);
14727 this.doQuery(this.getRawValue());
14731 onSearchFieldClick : function(e)
14733 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14734 this.onTickableFooterButtonClick(e, false, false);
14738 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14743 this.loadNext = false;
14744 this.hasFocus = true;
14746 if(this.triggerAction == 'all') {
14747 this.doQuery(this.allQuery, true);
14749 this.doQuery(this.getRawValue());
14753 listKeyPress : function(e)
14755 //Roo.log('listkeypress');
14756 // scroll to first matching element based on key pres..
14757 if (e.isSpecialKey()) {
14760 var k = String.fromCharCode(e.getKey()).toUpperCase();
14763 var csel = this.view.getSelectedNodes();
14764 var cselitem = false;
14766 var ix = this.view.indexOf(csel[0]);
14767 cselitem = this.store.getAt(ix);
14768 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14774 this.store.each(function(v) {
14776 // start at existing selection.
14777 if (cselitem.id == v.id) {
14783 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14784 match = this.store.indexOf(v);
14790 if (match === false) {
14791 return true; // no more action?
14794 this.view.select(match);
14795 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14796 sn.scrollIntoView(sn.dom.parentNode, false);
14799 onViewScroll : function(e, t){
14801 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){
14805 this.hasQuery = true;
14807 this.loading = this.list.select('.loading', true).first();
14809 if(this.loading === null){
14810 this.list.createChild({
14812 cls: 'loading roo-select2-more-results roo-select2-active',
14813 html: 'Loading more results...'
14816 this.loading = this.list.select('.loading', true).first();
14818 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14820 this.loading.hide();
14823 this.loading.show();
14828 this.loadNext = true;
14830 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14835 addItem : function(o)
14837 var dv = ''; // display value
14839 if (this.displayField) {
14840 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14842 // this is an error condition!!!
14843 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14850 var choice = this.choices.createChild({
14852 cls: 'roo-select2-search-choice',
14861 cls: 'roo-select2-search-choice-close fa fa-times',
14866 }, this.searchField);
14868 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14870 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14878 this.inputEl().dom.value = '';
14883 onRemoveItem : function(e, _self, o)
14885 e.preventDefault();
14887 this.lastItem = Roo.apply([], this.item);
14889 var index = this.item.indexOf(o.data) * 1;
14892 Roo.log('not this item?!');
14896 this.item.splice(index, 1);
14901 this.fireEvent('remove', this, e);
14907 syncValue : function()
14909 if(!this.item.length){
14916 Roo.each(this.item, function(i){
14917 if(_this.valueField){
14918 value.push(i[_this.valueField]);
14925 this.value = value.join(',');
14927 if(this.hiddenField){
14928 this.hiddenField.dom.value = this.value;
14931 this.store.fireEvent("datachanged", this.store);
14936 clearItem : function()
14938 if(!this.multiple){
14944 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14952 if(this.tickable && !Roo.isTouch){
14953 this.view.refresh();
14957 inputEl: function ()
14959 if(Roo.isIOS && this.useNativeIOS){
14960 return this.el.select('select.roo-ios-select', true).first();
14963 if(Roo.isTouch && this.mobileTouchView){
14964 return this.el.select('input.form-control',true).first();
14968 return this.searchField;
14971 return this.el.select('input.form-control',true).first();
14974 onTickableFooterButtonClick : function(e, btn, el)
14976 e.preventDefault();
14978 this.lastItem = Roo.apply([], this.item);
14980 if(btn && btn.name == 'cancel'){
14981 this.tickItems = Roo.apply([], this.item);
14990 Roo.each(this.tickItems, function(o){
14998 validate : function()
15000 if(this.getVisibilityEl().hasClass('hidden')){
15004 var v = this.getRawValue();
15007 v = this.getValue();
15010 if(this.disabled || this.allowBlank || v.length){
15015 this.markInvalid();
15019 tickableInputEl : function()
15021 if(!this.tickable || !this.editable){
15022 return this.inputEl();
15025 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15029 getAutoCreateTouchView : function()
15034 cls: 'form-group' //input-group
15040 type : this.inputType,
15041 cls : 'form-control x-combo-noedit',
15042 autocomplete: 'new-password',
15043 placeholder : this.placeholder || '',
15048 input.name = this.name;
15052 input.cls += ' input-' + this.size;
15055 if (this.disabled) {
15056 input.disabled = true;
15067 inputblock.cls += ' input-group';
15069 inputblock.cn.unshift({
15071 cls : 'input-group-addon input-group-prepend input-group-text',
15076 if(this.removable && !this.multiple){
15077 inputblock.cls += ' roo-removable';
15079 inputblock.cn.push({
15082 cls : 'roo-combo-removable-btn close'
15086 if(this.hasFeedback && !this.allowBlank){
15088 inputblock.cls += ' has-feedback';
15090 inputblock.cn.push({
15092 cls: 'glyphicon form-control-feedback'
15099 inputblock.cls += (this.before) ? '' : ' input-group';
15101 inputblock.cn.push({
15103 cls : 'input-group-addon input-group-append input-group-text',
15109 var ibwrap = inputblock;
15114 cls: 'roo-select2-choices',
15118 cls: 'roo-select2-search-field',
15131 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15136 cls: 'form-hidden-field'
15142 if(!this.multiple && this.showToggleBtn){
15149 if (this.caret != false) {
15152 cls: 'fa fa-' + this.caret
15159 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15164 cls: 'combobox-clear',
15178 combobox.cls += ' roo-select2-container-multi';
15181 var align = this.labelAlign || this.parentLabelAlign();
15183 if (align ==='left' && this.fieldLabel.length) {
15188 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15189 tooltip : 'This field is required'
15193 cls : 'control-label col-form-label',
15194 html : this.fieldLabel
15205 var labelCfg = cfg.cn[1];
15206 var contentCfg = cfg.cn[2];
15209 if(this.indicatorpos == 'right'){
15214 cls : 'control-label col-form-label',
15218 html : this.fieldLabel
15222 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15223 tooltip : 'This field is required'
15236 labelCfg = cfg.cn[0];
15237 contentCfg = cfg.cn[1];
15242 if(this.labelWidth > 12){
15243 labelCfg.style = "width: " + this.labelWidth + 'px';
15246 if(this.labelWidth < 13 && this.labelmd == 0){
15247 this.labelmd = this.labelWidth;
15250 if(this.labellg > 0){
15251 labelCfg.cls += ' col-lg-' + this.labellg;
15252 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15255 if(this.labelmd > 0){
15256 labelCfg.cls += ' col-md-' + this.labelmd;
15257 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15260 if(this.labelsm > 0){
15261 labelCfg.cls += ' col-sm-' + this.labelsm;
15262 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15265 if(this.labelxs > 0){
15266 labelCfg.cls += ' col-xs-' + this.labelxs;
15267 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15271 } else if ( this.fieldLabel.length) {
15275 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15276 tooltip : 'This field is required'
15280 cls : 'control-label',
15281 html : this.fieldLabel
15292 if(this.indicatorpos == 'right'){
15296 cls : 'control-label',
15297 html : this.fieldLabel,
15301 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15302 tooltip : 'This field is required'
15319 var settings = this;
15321 ['xs','sm','md','lg'].map(function(size){
15322 if (settings[size]) {
15323 cfg.cls += ' col-' + size + '-' + settings[size];
15330 initTouchView : function()
15332 this.renderTouchView();
15334 this.touchViewEl.on('scroll', function(){
15335 this.el.dom.scrollTop = 0;
15338 this.originalValue = this.getValue();
15340 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15342 this.inputEl().on("click", this.showTouchView, this);
15343 if (this.triggerEl) {
15344 this.triggerEl.on("click", this.showTouchView, this);
15348 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15349 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15351 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15353 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15354 this.store.on('load', this.onTouchViewLoad, this);
15355 this.store.on('loadexception', this.onTouchViewLoadException, this);
15357 if(this.hiddenName){
15359 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15361 this.hiddenField.dom.value =
15362 this.hiddenValue !== undefined ? this.hiddenValue :
15363 this.value !== undefined ? this.value : '';
15365 this.el.dom.removeAttribute('name');
15366 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15370 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15371 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15374 if(this.removable && !this.multiple){
15375 var close = this.closeTriggerEl();
15377 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15378 close.on('click', this.removeBtnClick, this, close);
15382 * fix the bug in Safari iOS8
15384 this.inputEl().on("focus", function(e){
15385 document.activeElement.blur();
15388 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15395 renderTouchView : function()
15397 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15398 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15400 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15401 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15403 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15404 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15405 this.touchViewBodyEl.setStyle('overflow', 'auto');
15407 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15408 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15410 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15411 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15415 showTouchView : function()
15421 this.touchViewHeaderEl.hide();
15423 if(this.modalTitle.length){
15424 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15425 this.touchViewHeaderEl.show();
15428 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15429 this.touchViewEl.show();
15431 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15433 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15434 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15436 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15438 if(this.modalTitle.length){
15439 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15442 this.touchViewBodyEl.setHeight(bodyHeight);
15446 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15448 this.touchViewEl.addClass('in');
15451 if(this._touchViewMask){
15452 Roo.get(document.body).addClass("x-body-masked");
15453 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15454 this._touchViewMask.setStyle('z-index', 10000);
15455 this._touchViewMask.addClass('show');
15458 this.doTouchViewQuery();
15462 hideTouchView : function()
15464 this.touchViewEl.removeClass('in');
15468 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15470 this.touchViewEl.setStyle('display', 'none');
15473 if(this._touchViewMask){
15474 this._touchViewMask.removeClass('show');
15475 Roo.get(document.body).removeClass("x-body-masked");
15479 setTouchViewValue : function()
15486 Roo.each(this.tickItems, function(o){
15491 this.hideTouchView();
15494 doTouchViewQuery : function()
15503 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15507 if(!this.alwaysQuery || this.mode == 'local'){
15508 this.onTouchViewLoad();
15515 onTouchViewBeforeLoad : function(combo,opts)
15521 onTouchViewLoad : function()
15523 if(this.store.getCount() < 1){
15524 this.onTouchViewEmptyResults();
15528 this.clearTouchView();
15530 var rawValue = this.getRawValue();
15532 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15534 this.tickItems = [];
15536 this.store.data.each(function(d, rowIndex){
15537 var row = this.touchViewListGroup.createChild(template);
15539 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15540 row.addClass(d.data.cls);
15543 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15546 html : d.data[this.displayField]
15549 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15550 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15553 row.removeClass('selected');
15554 if(!this.multiple && this.valueField &&
15555 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15558 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15559 row.addClass('selected');
15562 if(this.multiple && this.valueField &&
15563 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15567 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15568 this.tickItems.push(d.data);
15571 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15575 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15577 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15579 if(this.modalTitle.length){
15580 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15583 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15585 if(this.mobile_restrict_height && listHeight < bodyHeight){
15586 this.touchViewBodyEl.setHeight(listHeight);
15591 if(firstChecked && listHeight > bodyHeight){
15592 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15597 onTouchViewLoadException : function()
15599 this.hideTouchView();
15602 onTouchViewEmptyResults : function()
15604 this.clearTouchView();
15606 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15608 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15612 clearTouchView : function()
15614 this.touchViewListGroup.dom.innerHTML = '';
15617 onTouchViewClick : function(e, el, o)
15619 e.preventDefault();
15622 var rowIndex = o.rowIndex;
15624 var r = this.store.getAt(rowIndex);
15626 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15628 if(!this.multiple){
15629 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15630 c.dom.removeAttribute('checked');
15633 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15635 this.setFromData(r.data);
15637 var close = this.closeTriggerEl();
15643 this.hideTouchView();
15645 this.fireEvent('select', this, r, rowIndex);
15650 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15651 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15652 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15656 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15657 this.addItem(r.data);
15658 this.tickItems.push(r.data);
15662 getAutoCreateNativeIOS : function()
15665 cls: 'form-group' //input-group,
15670 cls : 'roo-ios-select'
15674 combobox.name = this.name;
15677 if (this.disabled) {
15678 combobox.disabled = true;
15681 var settings = this;
15683 ['xs','sm','md','lg'].map(function(size){
15684 if (settings[size]) {
15685 cfg.cls += ' col-' + size + '-' + settings[size];
15695 initIOSView : function()
15697 this.store.on('load', this.onIOSViewLoad, this);
15702 onIOSViewLoad : function()
15704 if(this.store.getCount() < 1){
15708 this.clearIOSView();
15710 if(this.allowBlank) {
15712 var default_text = '-- SELECT --';
15714 if(this.placeholder.length){
15715 default_text = this.placeholder;
15718 if(this.emptyTitle.length){
15719 default_text += ' - ' + this.emptyTitle + ' -';
15722 var opt = this.inputEl().createChild({
15725 html : default_text
15729 o[this.valueField] = 0;
15730 o[this.displayField] = default_text;
15732 this.ios_options.push({
15739 this.store.data.each(function(d, rowIndex){
15743 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15744 html = d.data[this.displayField];
15749 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15750 value = d.data[this.valueField];
15759 if(this.value == d.data[this.valueField]){
15760 option['selected'] = true;
15763 var opt = this.inputEl().createChild(option);
15765 this.ios_options.push({
15772 this.inputEl().on('change', function(){
15773 this.fireEvent('select', this);
15778 clearIOSView: function()
15780 this.inputEl().dom.innerHTML = '';
15782 this.ios_options = [];
15785 setIOSValue: function(v)
15789 if(!this.ios_options){
15793 Roo.each(this.ios_options, function(opts){
15795 opts.el.dom.removeAttribute('selected');
15797 if(opts.data[this.valueField] != v){
15801 opts.el.dom.setAttribute('selected', true);
15807 * @cfg {Boolean} grow
15811 * @cfg {Number} growMin
15815 * @cfg {Number} growMax
15824 Roo.apply(Roo.bootstrap.ComboBox, {
15828 cls: 'modal-header',
15850 cls: 'list-group-item',
15854 cls: 'roo-combobox-list-group-item-value'
15858 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15872 listItemCheckbox : {
15874 cls: 'list-group-item',
15878 cls: 'roo-combobox-list-group-item-value'
15882 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15898 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15903 cls: 'modal-footer',
15911 cls: 'col-xs-6 text-left',
15914 cls: 'btn btn-danger roo-touch-view-cancel',
15920 cls: 'col-xs-6 text-right',
15923 cls: 'btn btn-success roo-touch-view-ok',
15934 Roo.apply(Roo.bootstrap.ComboBox, {
15936 touchViewTemplate : {
15938 cls: 'modal fade roo-combobox-touch-view',
15942 cls: 'modal-dialog',
15943 style : 'position:fixed', // we have to fix position....
15947 cls: 'modal-content',
15949 Roo.bootstrap.ComboBox.header,
15950 Roo.bootstrap.ComboBox.body,
15951 Roo.bootstrap.ComboBox.footer
15960 * Ext JS Library 1.1.1
15961 * Copyright(c) 2006-2007, Ext JS, LLC.
15963 * Originally Released Under LGPL - original licence link has changed is not relivant.
15966 * <script type="text/javascript">
15971 * @extends Roo.util.Observable
15972 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15973 * This class also supports single and multi selection modes. <br>
15974 * Create a data model bound view:
15976 var store = new Roo.data.Store(...);
15978 var view = new Roo.View({
15980 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
15982 singleSelect: true,
15983 selectedClass: "ydataview-selected",
15987 // listen for node click?
15988 view.on("click", function(vw, index, node, e){
15989 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15993 dataModel.load("foobar.xml");
15995 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15997 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15998 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16000 * Note: old style constructor is still suported (container, template, config)
16003 * Create a new View
16004 * @param {Object} config The config object
16007 Roo.View = function(config, depreciated_tpl, depreciated_config){
16009 this.parent = false;
16011 if (typeof(depreciated_tpl) == 'undefined') {
16012 // new way.. - universal constructor.
16013 Roo.apply(this, config);
16014 this.el = Roo.get(this.el);
16017 this.el = Roo.get(config);
16018 this.tpl = depreciated_tpl;
16019 Roo.apply(this, depreciated_config);
16021 this.wrapEl = this.el.wrap().wrap();
16022 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16025 if(typeof(this.tpl) == "string"){
16026 this.tpl = new Roo.Template(this.tpl);
16028 // support xtype ctors..
16029 this.tpl = new Roo.factory(this.tpl, Roo);
16033 this.tpl.compile();
16038 * @event beforeclick
16039 * Fires before a click is processed. Returns false to cancel the default action.
16040 * @param {Roo.View} this
16041 * @param {Number} index The index of the target node
16042 * @param {HTMLElement} node The target node
16043 * @param {Roo.EventObject} e The raw event object
16045 "beforeclick" : true,
16048 * Fires when a template node is clicked.
16049 * @param {Roo.View} this
16050 * @param {Number} index The index of the target node
16051 * @param {HTMLElement} node The target node
16052 * @param {Roo.EventObject} e The raw event object
16057 * Fires when a template node is double clicked.
16058 * @param {Roo.View} this
16059 * @param {Number} index The index of the target node
16060 * @param {HTMLElement} node The target node
16061 * @param {Roo.EventObject} e The raw event object
16065 * @event contextmenu
16066 * Fires when a template node is right clicked.
16067 * @param {Roo.View} this
16068 * @param {Number} index The index of the target node
16069 * @param {HTMLElement} node The target node
16070 * @param {Roo.EventObject} e The raw event object
16072 "contextmenu" : true,
16074 * @event selectionchange
16075 * Fires when the selected nodes change.
16076 * @param {Roo.View} this
16077 * @param {Array} selections Array of the selected nodes
16079 "selectionchange" : true,
16082 * @event beforeselect
16083 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16084 * @param {Roo.View} this
16085 * @param {HTMLElement} node The node to be selected
16086 * @param {Array} selections Array of currently selected nodes
16088 "beforeselect" : true,
16090 * @event preparedata
16091 * Fires on every row to render, to allow you to change the data.
16092 * @param {Roo.View} this
16093 * @param {Object} data to be rendered (change this)
16095 "preparedata" : true
16103 "click": this.onClick,
16104 "dblclick": this.onDblClick,
16105 "contextmenu": this.onContextMenu,
16109 this.selections = [];
16111 this.cmp = new Roo.CompositeElementLite([]);
16113 this.store = Roo.factory(this.store, Roo.data);
16114 this.setStore(this.store, true);
16117 if ( this.footer && this.footer.xtype) {
16119 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16121 this.footer.dataSource = this.store;
16122 this.footer.container = fctr;
16123 this.footer = Roo.factory(this.footer, Roo);
16124 fctr.insertFirst(this.el);
16126 // this is a bit insane - as the paging toolbar seems to detach the el..
16127 // dom.parentNode.parentNode.parentNode
16128 // they get detached?
16132 Roo.View.superclass.constructor.call(this);
16137 Roo.extend(Roo.View, Roo.util.Observable, {
16140 * @cfg {Roo.data.Store} store Data store to load data from.
16145 * @cfg {String|Roo.Element} el The container element.
16150 * @cfg {String|Roo.Template} tpl The template used by this View
16154 * @cfg {String} dataName the named area of the template to use as the data area
16155 * Works with domtemplates roo-name="name"
16159 * @cfg {String} selectedClass The css class to add to selected nodes
16161 selectedClass : "x-view-selected",
16163 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16168 * @cfg {String} text to display on mask (default Loading)
16172 * @cfg {Boolean} multiSelect Allow multiple selection
16174 multiSelect : false,
16176 * @cfg {Boolean} singleSelect Allow single selection
16178 singleSelect: false,
16181 * @cfg {Boolean} toggleSelect - selecting
16183 toggleSelect : false,
16186 * @cfg {Boolean} tickable - selecting
16191 * Returns the element this view is bound to.
16192 * @return {Roo.Element}
16194 getEl : function(){
16195 return this.wrapEl;
16201 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16203 refresh : function(){
16204 //Roo.log('refresh');
16207 // if we are using something like 'domtemplate', then
16208 // the what gets used is:
16209 // t.applySubtemplate(NAME, data, wrapping data..)
16210 // the outer template then get' applied with
16211 // the store 'extra data'
16212 // and the body get's added to the
16213 // roo-name="data" node?
16214 // <span class='roo-tpl-{name}'></span> ?????
16218 this.clearSelections();
16219 this.el.update("");
16221 var records = this.store.getRange();
16222 if(records.length < 1) {
16224 // is this valid?? = should it render a template??
16226 this.el.update(this.emptyText);
16230 if (this.dataName) {
16231 this.el.update(t.apply(this.store.meta)); //????
16232 el = this.el.child('.roo-tpl-' + this.dataName);
16235 for(var i = 0, len = records.length; i < len; i++){
16236 var data = this.prepareData(records[i].data, i, records[i]);
16237 this.fireEvent("preparedata", this, data, i, records[i]);
16239 var d = Roo.apply({}, data);
16242 Roo.apply(d, {'roo-id' : Roo.id()});
16246 Roo.each(this.parent.item, function(item){
16247 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16250 Roo.apply(d, {'roo-data-checked' : 'checked'});
16254 html[html.length] = Roo.util.Format.trim(
16256 t.applySubtemplate(this.dataName, d, this.store.meta) :
16263 el.update(html.join(""));
16264 this.nodes = el.dom.childNodes;
16265 this.updateIndexes(0);
16270 * Function to override to reformat the data that is sent to
16271 * the template for each node.
16272 * DEPRICATED - use the preparedata event handler.
16273 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16274 * a JSON object for an UpdateManager bound view).
16276 prepareData : function(data, index, record)
16278 this.fireEvent("preparedata", this, data, index, record);
16282 onUpdate : function(ds, record){
16283 // Roo.log('on update');
16284 this.clearSelections();
16285 var index = this.store.indexOf(record);
16286 var n = this.nodes[index];
16287 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16288 n.parentNode.removeChild(n);
16289 this.updateIndexes(index, index);
16295 onAdd : function(ds, records, index)
16297 //Roo.log(['on Add', ds, records, index] );
16298 this.clearSelections();
16299 if(this.nodes.length == 0){
16303 var n = this.nodes[index];
16304 for(var i = 0, len = records.length; i < len; i++){
16305 var d = this.prepareData(records[i].data, i, records[i]);
16307 this.tpl.insertBefore(n, d);
16310 this.tpl.append(this.el, d);
16313 this.updateIndexes(index);
16316 onRemove : function(ds, record, index){
16317 // Roo.log('onRemove');
16318 this.clearSelections();
16319 var el = this.dataName ?
16320 this.el.child('.roo-tpl-' + this.dataName) :
16323 el.dom.removeChild(this.nodes[index]);
16324 this.updateIndexes(index);
16328 * Refresh an individual node.
16329 * @param {Number} index
16331 refreshNode : function(index){
16332 this.onUpdate(this.store, this.store.getAt(index));
16335 updateIndexes : function(startIndex, endIndex){
16336 var ns = this.nodes;
16337 startIndex = startIndex || 0;
16338 endIndex = endIndex || ns.length - 1;
16339 for(var i = startIndex; i <= endIndex; i++){
16340 ns[i].nodeIndex = i;
16345 * Changes the data store this view uses and refresh the view.
16346 * @param {Store} store
16348 setStore : function(store, initial){
16349 if(!initial && this.store){
16350 this.store.un("datachanged", this.refresh);
16351 this.store.un("add", this.onAdd);
16352 this.store.un("remove", this.onRemove);
16353 this.store.un("update", this.onUpdate);
16354 this.store.un("clear", this.refresh);
16355 this.store.un("beforeload", this.onBeforeLoad);
16356 this.store.un("load", this.onLoad);
16357 this.store.un("loadexception", this.onLoad);
16361 store.on("datachanged", this.refresh, this);
16362 store.on("add", this.onAdd, this);
16363 store.on("remove", this.onRemove, this);
16364 store.on("update", this.onUpdate, this);
16365 store.on("clear", this.refresh, this);
16366 store.on("beforeload", this.onBeforeLoad, this);
16367 store.on("load", this.onLoad, this);
16368 store.on("loadexception", this.onLoad, this);
16376 * onbeforeLoad - masks the loading area.
16379 onBeforeLoad : function(store,opts)
16381 //Roo.log('onBeforeLoad');
16383 this.el.update("");
16385 this.el.mask(this.mask ? this.mask : "Loading" );
16387 onLoad : function ()
16394 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16395 * @param {HTMLElement} node
16396 * @return {HTMLElement} The template node
16398 findItemFromChild : function(node){
16399 var el = this.dataName ?
16400 this.el.child('.roo-tpl-' + this.dataName,true) :
16403 if(!node || node.parentNode == el){
16406 var p = node.parentNode;
16407 while(p && p != el){
16408 if(p.parentNode == el){
16417 onClick : function(e){
16418 var item = this.findItemFromChild(e.getTarget());
16420 var index = this.indexOf(item);
16421 if(this.onItemClick(item, index, e) !== false){
16422 this.fireEvent("click", this, index, item, e);
16425 this.clearSelections();
16430 onContextMenu : function(e){
16431 var item = this.findItemFromChild(e.getTarget());
16433 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16438 onDblClick : function(e){
16439 var item = this.findItemFromChild(e.getTarget());
16441 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16445 onItemClick : function(item, index, e)
16447 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16450 if (this.toggleSelect) {
16451 var m = this.isSelected(item) ? 'unselect' : 'select';
16454 _t[m](item, true, false);
16457 if(this.multiSelect || this.singleSelect){
16458 if(this.multiSelect && e.shiftKey && this.lastSelection){
16459 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16461 this.select(item, this.multiSelect && e.ctrlKey);
16462 this.lastSelection = item;
16465 if(!this.tickable){
16466 e.preventDefault();
16474 * Get the number of selected nodes.
16477 getSelectionCount : function(){
16478 return this.selections.length;
16482 * Get the currently selected nodes.
16483 * @return {Array} An array of HTMLElements
16485 getSelectedNodes : function(){
16486 return this.selections;
16490 * Get the indexes of the selected nodes.
16493 getSelectedIndexes : function(){
16494 var indexes = [], s = this.selections;
16495 for(var i = 0, len = s.length; i < len; i++){
16496 indexes.push(s[i].nodeIndex);
16502 * Clear all selections
16503 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16505 clearSelections : function(suppressEvent){
16506 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16507 this.cmp.elements = this.selections;
16508 this.cmp.removeClass(this.selectedClass);
16509 this.selections = [];
16510 if(!suppressEvent){
16511 this.fireEvent("selectionchange", this, this.selections);
16517 * Returns true if the passed node is selected
16518 * @param {HTMLElement/Number} node The node or node index
16519 * @return {Boolean}
16521 isSelected : function(node){
16522 var s = this.selections;
16526 node = this.getNode(node);
16527 return s.indexOf(node) !== -1;
16532 * @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
16533 * @param {Boolean} keepExisting (optional) true to keep existing selections
16534 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16536 select : function(nodeInfo, keepExisting, suppressEvent){
16537 if(nodeInfo instanceof Array){
16539 this.clearSelections(true);
16541 for(var i = 0, len = nodeInfo.length; i < len; i++){
16542 this.select(nodeInfo[i], true, true);
16546 var node = this.getNode(nodeInfo);
16547 if(!node || this.isSelected(node)){
16548 return; // already selected.
16551 this.clearSelections(true);
16554 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16555 Roo.fly(node).addClass(this.selectedClass);
16556 this.selections.push(node);
16557 if(!suppressEvent){
16558 this.fireEvent("selectionchange", this, this.selections);
16566 * @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
16567 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16568 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16570 unselect : function(nodeInfo, keepExisting, suppressEvent)
16572 if(nodeInfo instanceof Array){
16573 Roo.each(this.selections, function(s) {
16574 this.unselect(s, nodeInfo);
16578 var node = this.getNode(nodeInfo);
16579 if(!node || !this.isSelected(node)){
16580 //Roo.log("not selected");
16581 return; // not selected.
16585 Roo.each(this.selections, function(s) {
16587 Roo.fly(node).removeClass(this.selectedClass);
16594 this.selections= ns;
16595 this.fireEvent("selectionchange", this, this.selections);
16599 * Gets a template node.
16600 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16601 * @return {HTMLElement} The node or null if it wasn't found
16603 getNode : function(nodeInfo){
16604 if(typeof nodeInfo == "string"){
16605 return document.getElementById(nodeInfo);
16606 }else if(typeof nodeInfo == "number"){
16607 return this.nodes[nodeInfo];
16613 * Gets a range template nodes.
16614 * @param {Number} startIndex
16615 * @param {Number} endIndex
16616 * @return {Array} An array of nodes
16618 getNodes : function(start, end){
16619 var ns = this.nodes;
16620 start = start || 0;
16621 end = typeof end == "undefined" ? ns.length - 1 : end;
16624 for(var i = start; i <= end; i++){
16628 for(var i = start; i >= end; i--){
16636 * Finds the index of the passed node
16637 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16638 * @return {Number} The index of the node or -1
16640 indexOf : function(node){
16641 node = this.getNode(node);
16642 if(typeof node.nodeIndex == "number"){
16643 return node.nodeIndex;
16645 var ns = this.nodes;
16646 for(var i = 0, len = ns.length; i < len; i++){
16657 * based on jquery fullcalendar
16661 Roo.bootstrap = Roo.bootstrap || {};
16663 * @class Roo.bootstrap.Calendar
16664 * @extends Roo.bootstrap.Component
16665 * Bootstrap Calendar class
16666 * @cfg {Boolean} loadMask (true|false) default false
16667 * @cfg {Object} header generate the user specific header of the calendar, default false
16670 * Create a new Container
16671 * @param {Object} config The config object
16676 Roo.bootstrap.Calendar = function(config){
16677 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16681 * Fires when a date is selected
16682 * @param {DatePicker} this
16683 * @param {Date} date The selected date
16687 * @event monthchange
16688 * Fires when the displayed month changes
16689 * @param {DatePicker} this
16690 * @param {Date} date The selected month
16692 'monthchange': true,
16694 * @event evententer
16695 * Fires when mouse over an event
16696 * @param {Calendar} this
16697 * @param {event} Event
16699 'evententer': true,
16701 * @event eventleave
16702 * Fires when the mouse leaves an
16703 * @param {Calendar} this
16706 'eventleave': true,
16708 * @event eventclick
16709 * Fires when the mouse click an
16710 * @param {Calendar} this
16719 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16722 * @cfg {Number} startDay
16723 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16731 getAutoCreate : function(){
16734 var fc_button = function(name, corner, style, content ) {
16735 return Roo.apply({},{
16737 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16739 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16742 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16753 style : 'width:100%',
16760 cls : 'fc-header-left',
16762 fc_button('prev', 'left', 'arrow', '‹' ),
16763 fc_button('next', 'right', 'arrow', '›' ),
16764 { tag: 'span', cls: 'fc-header-space' },
16765 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16773 cls : 'fc-header-center',
16777 cls: 'fc-header-title',
16780 html : 'month / year'
16788 cls : 'fc-header-right',
16790 /* fc_button('month', 'left', '', 'month' ),
16791 fc_button('week', '', '', 'week' ),
16792 fc_button('day', 'right', '', 'day' )
16804 header = this.header;
16807 var cal_heads = function() {
16809 // fixme - handle this.
16811 for (var i =0; i < Date.dayNames.length; i++) {
16812 var d = Date.dayNames[i];
16815 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16816 html : d.substring(0,3)
16820 ret[0].cls += ' fc-first';
16821 ret[6].cls += ' fc-last';
16824 var cal_cell = function(n) {
16827 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16832 cls: 'fc-day-number',
16836 cls: 'fc-day-content',
16840 style: 'position: relative;' // height: 17px;
16852 var cal_rows = function() {
16855 for (var r = 0; r < 6; r++) {
16862 for (var i =0; i < Date.dayNames.length; i++) {
16863 var d = Date.dayNames[i];
16864 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16867 row.cn[0].cls+=' fc-first';
16868 row.cn[0].cn[0].style = 'min-height:90px';
16869 row.cn[6].cls+=' fc-last';
16873 ret[0].cls += ' fc-first';
16874 ret[4].cls += ' fc-prev-last';
16875 ret[5].cls += ' fc-last';
16882 cls: 'fc-border-separate',
16883 style : 'width:100%',
16891 cls : 'fc-first fc-last',
16909 cls : 'fc-content',
16910 style : "position: relative;",
16913 cls : 'fc-view fc-view-month fc-grid',
16914 style : 'position: relative',
16915 unselectable : 'on',
16918 cls : 'fc-event-container',
16919 style : 'position:absolute;z-index:8;top:0;left:0;'
16937 initEvents : function()
16940 throw "can not find store for calendar";
16946 style: "text-align:center",
16950 style: "background-color:white;width:50%;margin:250 auto",
16954 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16965 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16967 var size = this.el.select('.fc-content', true).first().getSize();
16968 this.maskEl.setSize(size.width, size.height);
16969 this.maskEl.enableDisplayMode("block");
16970 if(!this.loadMask){
16971 this.maskEl.hide();
16974 this.store = Roo.factory(this.store, Roo.data);
16975 this.store.on('load', this.onLoad, this);
16976 this.store.on('beforeload', this.onBeforeLoad, this);
16980 this.cells = this.el.select('.fc-day',true);
16981 //Roo.log(this.cells);
16982 this.textNodes = this.el.query('.fc-day-number');
16983 this.cells.addClassOnOver('fc-state-hover');
16985 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16986 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16987 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16988 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16990 this.on('monthchange', this.onMonthChange, this);
16992 this.update(new Date().clearTime());
16995 resize : function() {
16996 var sz = this.el.getSize();
16998 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16999 this.el.select('.fc-day-content div',true).setHeight(34);
17004 showPrevMonth : function(e){
17005 this.update(this.activeDate.add("mo", -1));
17007 showToday : function(e){
17008 this.update(new Date().clearTime());
17011 showNextMonth : function(e){
17012 this.update(this.activeDate.add("mo", 1));
17016 showPrevYear : function(){
17017 this.update(this.activeDate.add("y", -1));
17021 showNextYear : function(){
17022 this.update(this.activeDate.add("y", 1));
17027 update : function(date)
17029 var vd = this.activeDate;
17030 this.activeDate = date;
17031 // if(vd && this.el){
17032 // var t = date.getTime();
17033 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17034 // Roo.log('using add remove');
17036 // this.fireEvent('monthchange', this, date);
17038 // this.cells.removeClass("fc-state-highlight");
17039 // this.cells.each(function(c){
17040 // if(c.dateValue == t){
17041 // c.addClass("fc-state-highlight");
17042 // setTimeout(function(){
17043 // try{c.dom.firstChild.focus();}catch(e){}
17053 var days = date.getDaysInMonth();
17055 var firstOfMonth = date.getFirstDateOfMonth();
17056 var startingPos = firstOfMonth.getDay()-this.startDay;
17058 if(startingPos < this.startDay){
17062 var pm = date.add(Date.MONTH, -1);
17063 var prevStart = pm.getDaysInMonth()-startingPos;
17065 this.cells = this.el.select('.fc-day',true);
17066 this.textNodes = this.el.query('.fc-day-number');
17067 this.cells.addClassOnOver('fc-state-hover');
17069 var cells = this.cells.elements;
17070 var textEls = this.textNodes;
17072 Roo.each(cells, function(cell){
17073 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17076 days += startingPos;
17078 // convert everything to numbers so it's fast
17079 var day = 86400000;
17080 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17083 //Roo.log(prevStart);
17085 var today = new Date().clearTime().getTime();
17086 var sel = date.clearTime().getTime();
17087 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17088 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17089 var ddMatch = this.disabledDatesRE;
17090 var ddText = this.disabledDatesText;
17091 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17092 var ddaysText = this.disabledDaysText;
17093 var format = this.format;
17095 var setCellClass = function(cal, cell){
17099 //Roo.log('set Cell Class');
17101 var t = d.getTime();
17105 cell.dateValue = t;
17107 cell.className += " fc-today";
17108 cell.className += " fc-state-highlight";
17109 cell.title = cal.todayText;
17112 // disable highlight in other month..
17113 //cell.className += " fc-state-highlight";
17118 cell.className = " fc-state-disabled";
17119 cell.title = cal.minText;
17123 cell.className = " fc-state-disabled";
17124 cell.title = cal.maxText;
17128 if(ddays.indexOf(d.getDay()) != -1){
17129 cell.title = ddaysText;
17130 cell.className = " fc-state-disabled";
17133 if(ddMatch && format){
17134 var fvalue = d.dateFormat(format);
17135 if(ddMatch.test(fvalue)){
17136 cell.title = ddText.replace("%0", fvalue);
17137 cell.className = " fc-state-disabled";
17141 if (!cell.initialClassName) {
17142 cell.initialClassName = cell.dom.className;
17145 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17150 for(; i < startingPos; i++) {
17151 textEls[i].innerHTML = (++prevStart);
17152 d.setDate(d.getDate()+1);
17154 cells[i].className = "fc-past fc-other-month";
17155 setCellClass(this, cells[i]);
17160 for(; i < days; i++){
17161 intDay = i - startingPos + 1;
17162 textEls[i].innerHTML = (intDay);
17163 d.setDate(d.getDate()+1);
17165 cells[i].className = ''; // "x-date-active";
17166 setCellClass(this, cells[i]);
17170 for(; i < 42; i++) {
17171 textEls[i].innerHTML = (++extraDays);
17172 d.setDate(d.getDate()+1);
17174 cells[i].className = "fc-future fc-other-month";
17175 setCellClass(this, cells[i]);
17178 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17180 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17182 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17183 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17185 if(totalRows != 6){
17186 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17187 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17190 this.fireEvent('monthchange', this, date);
17194 if(!this.internalRender){
17195 var main = this.el.dom.firstChild;
17196 var w = main.offsetWidth;
17197 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17198 Roo.fly(main).setWidth(w);
17199 this.internalRender = true;
17200 // opera does not respect the auto grow header center column
17201 // then, after it gets a width opera refuses to recalculate
17202 // without a second pass
17203 if(Roo.isOpera && !this.secondPass){
17204 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17205 this.secondPass = true;
17206 this.update.defer(10, this, [date]);
17213 findCell : function(dt) {
17214 dt = dt.clearTime().getTime();
17216 this.cells.each(function(c){
17217 //Roo.log("check " +c.dateValue + '?=' + dt);
17218 if(c.dateValue == dt){
17228 findCells : function(ev) {
17229 var s = ev.start.clone().clearTime().getTime();
17231 var e= ev.end.clone().clearTime().getTime();
17234 this.cells.each(function(c){
17235 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17237 if(c.dateValue > e){
17240 if(c.dateValue < s){
17249 // findBestRow: function(cells)
17253 // for (var i =0 ; i < cells.length;i++) {
17254 // ret = Math.max(cells[i].rows || 0,ret);
17261 addItem : function(ev)
17263 // look for vertical location slot in
17264 var cells = this.findCells(ev);
17266 // ev.row = this.findBestRow(cells);
17268 // work out the location.
17272 for(var i =0; i < cells.length; i++) {
17274 cells[i].row = cells[0].row;
17277 cells[i].row = cells[i].row + 1;
17287 if (crow.start.getY() == cells[i].getY()) {
17289 crow.end = cells[i];
17306 cells[0].events.push(ev);
17308 this.calevents.push(ev);
17311 clearEvents: function() {
17313 if(!this.calevents){
17317 Roo.each(this.cells.elements, function(c){
17323 Roo.each(this.calevents, function(e) {
17324 Roo.each(e.els, function(el) {
17325 el.un('mouseenter' ,this.onEventEnter, this);
17326 el.un('mouseleave' ,this.onEventLeave, this);
17331 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17337 renderEvents: function()
17341 this.cells.each(function(c) {
17350 if(c.row != c.events.length){
17351 r = 4 - (4 - (c.row - c.events.length));
17354 c.events = ev.slice(0, r);
17355 c.more = ev.slice(r);
17357 if(c.more.length && c.more.length == 1){
17358 c.events.push(c.more.pop());
17361 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17365 this.cells.each(function(c) {
17367 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17370 for (var e = 0; e < c.events.length; e++){
17371 var ev = c.events[e];
17372 var rows = ev.rows;
17374 for(var i = 0; i < rows.length; i++) {
17376 // how many rows should it span..
17379 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17380 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17382 unselectable : "on",
17385 cls: 'fc-event-inner',
17389 // cls: 'fc-event-time',
17390 // html : cells.length > 1 ? '' : ev.time
17394 cls: 'fc-event-title',
17395 html : String.format('{0}', ev.title)
17402 cls: 'ui-resizable-handle ui-resizable-e',
17403 html : '  '
17410 cfg.cls += ' fc-event-start';
17412 if ((i+1) == rows.length) {
17413 cfg.cls += ' fc-event-end';
17416 var ctr = _this.el.select('.fc-event-container',true).first();
17417 var cg = ctr.createChild(cfg);
17419 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17420 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17422 var r = (c.more.length) ? 1 : 0;
17423 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17424 cg.setWidth(ebox.right - sbox.x -2);
17426 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17427 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17428 cg.on('click', _this.onEventClick, _this, ev);
17439 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17440 style : 'position: absolute',
17441 unselectable : "on",
17444 cls: 'fc-event-inner',
17448 cls: 'fc-event-title',
17456 cls: 'ui-resizable-handle ui-resizable-e',
17457 html : '  '
17463 var ctr = _this.el.select('.fc-event-container',true).first();
17464 var cg = ctr.createChild(cfg);
17466 var sbox = c.select('.fc-day-content',true).first().getBox();
17467 var ebox = c.select('.fc-day-content',true).first().getBox();
17469 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17470 cg.setWidth(ebox.right - sbox.x -2);
17472 cg.on('click', _this.onMoreEventClick, _this, c.more);
17482 onEventEnter: function (e, el,event,d) {
17483 this.fireEvent('evententer', this, el, event);
17486 onEventLeave: function (e, el,event,d) {
17487 this.fireEvent('eventleave', this, el, event);
17490 onEventClick: function (e, el,event,d) {
17491 this.fireEvent('eventclick', this, el, event);
17494 onMonthChange: function () {
17498 onMoreEventClick: function(e, el, more)
17502 this.calpopover.placement = 'right';
17503 this.calpopover.setTitle('More');
17505 this.calpopover.setContent('');
17507 var ctr = this.calpopover.el.select('.popover-content', true).first();
17509 Roo.each(more, function(m){
17511 cls : 'fc-event-hori fc-event-draggable',
17514 var cg = ctr.createChild(cfg);
17516 cg.on('click', _this.onEventClick, _this, m);
17519 this.calpopover.show(el);
17524 onLoad: function ()
17526 this.calevents = [];
17529 if(this.store.getCount() > 0){
17530 this.store.data.each(function(d){
17533 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17534 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17535 time : d.data.start_time,
17536 title : d.data.title,
17537 description : d.data.description,
17538 venue : d.data.venue
17543 this.renderEvents();
17545 if(this.calevents.length && this.loadMask){
17546 this.maskEl.hide();
17550 onBeforeLoad: function()
17552 this.clearEvents();
17554 this.maskEl.show();
17568 * @class Roo.bootstrap.Popover
17569 * @extends Roo.bootstrap.Component
17570 * Bootstrap Popover class
17571 * @cfg {String} html contents of the popover (or false to use children..)
17572 * @cfg {String} title of popover (or false to hide)
17573 * @cfg {String} placement how it is placed
17574 * @cfg {String} trigger click || hover (or false to trigger manually)
17575 * @cfg {String} over what (parent or false to trigger manually.)
17576 * @cfg {Number} delay - delay before showing
17579 * Create a new Popover
17580 * @param {Object} config The config object
17583 Roo.bootstrap.Popover = function(config){
17584 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17590 * After the popover show
17592 * @param {Roo.bootstrap.Popover} this
17597 * After the popover hide
17599 * @param {Roo.bootstrap.Popover} this
17605 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17607 title: 'Fill in a title',
17610 placement : 'right',
17611 trigger : 'hover', // hover
17617 can_build_overlaid : false,
17619 getChildContainer : function()
17621 return this.el.select('.popover-content',true).first();
17624 getAutoCreate : function(){
17627 cls : 'popover roo-dynamic',
17628 style: 'display:block',
17634 cls : 'popover-inner',
17638 cls: 'popover-title popover-header',
17642 cls : 'popover-content popover-body',
17653 setTitle: function(str)
17656 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17658 setContent: function(str)
17661 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17663 // as it get's added to the bottom of the page.
17664 onRender : function(ct, position)
17666 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17668 var cfg = Roo.apply({}, this.getAutoCreate());
17672 cfg.cls += ' ' + this.cls;
17675 cfg.style = this.style;
17677 //Roo.log("adding to ");
17678 this.el = Roo.get(document.body).createChild(cfg, position);
17679 // Roo.log(this.el);
17684 initEvents : function()
17686 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17687 this.el.enableDisplayMode('block');
17689 if (this.over === false) {
17692 if (this.triggers === false) {
17695 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17696 var triggers = this.trigger ? this.trigger.split(' ') : [];
17697 Roo.each(triggers, function(trigger) {
17699 if (trigger == 'click') {
17700 on_el.on('click', this.toggle, this);
17701 } else if (trigger != 'manual') {
17702 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17703 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17705 on_el.on(eventIn ,this.enter, this);
17706 on_el.on(eventOut, this.leave, this);
17717 toggle : function () {
17718 this.hoverState == 'in' ? this.leave() : this.enter();
17721 enter : function () {
17723 clearTimeout(this.timeout);
17725 this.hoverState = 'in';
17727 if (!this.delay || !this.delay.show) {
17732 this.timeout = setTimeout(function () {
17733 if (_t.hoverState == 'in') {
17736 }, this.delay.show)
17739 leave : function() {
17740 clearTimeout(this.timeout);
17742 this.hoverState = 'out';
17744 if (!this.delay || !this.delay.hide) {
17749 this.timeout = setTimeout(function () {
17750 if (_t.hoverState == 'out') {
17753 }, this.delay.hide)
17756 show : function (on_el)
17759 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17763 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17764 if (this.html !== false) {
17765 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17767 this.el.removeClass([
17768 'fade','top','bottom', 'left', 'right','in',
17769 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17771 if (!this.title.length) {
17772 this.el.select('.popover-title',true).hide();
17775 var placement = typeof this.placement == 'function' ?
17776 this.placement.call(this, this.el, on_el) :
17779 var autoToken = /\s?auto?\s?/i;
17780 var autoPlace = autoToken.test(placement);
17782 placement = placement.replace(autoToken, '') || 'top';
17786 //this.el.setXY([0,0]);
17788 this.el.dom.style.display='block';
17789 this.el.addClass(placement);
17791 //this.el.appendTo(on_el);
17793 var p = this.getPosition();
17794 var box = this.el.getBox();
17799 var align = Roo.bootstrap.Popover.alignment[placement];
17802 this.el.alignTo(on_el, align[0],align[1]);
17803 //var arrow = this.el.select('.arrow',true).first();
17804 //arrow.set(align[2],
17806 this.el.addClass('in');
17809 if (this.el.hasClass('fade')) {
17813 this.hoverState = 'in';
17815 this.fireEvent('show', this);
17820 this.el.setXY([0,0]);
17821 this.el.removeClass('in');
17823 this.hoverState = null;
17825 this.fireEvent('hide', this);
17830 Roo.bootstrap.Popover.alignment = {
17831 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17832 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17833 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17834 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17845 * @class Roo.bootstrap.Progress
17846 * @extends Roo.bootstrap.Component
17847 * Bootstrap Progress class
17848 * @cfg {Boolean} striped striped of the progress bar
17849 * @cfg {Boolean} active animated of the progress bar
17853 * Create a new Progress
17854 * @param {Object} config The config object
17857 Roo.bootstrap.Progress = function(config){
17858 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17861 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17866 getAutoCreate : function(){
17874 cfg.cls += ' progress-striped';
17878 cfg.cls += ' active';
17897 * @class Roo.bootstrap.ProgressBar
17898 * @extends Roo.bootstrap.Component
17899 * Bootstrap ProgressBar class
17900 * @cfg {Number} aria_valuenow aria-value now
17901 * @cfg {Number} aria_valuemin aria-value min
17902 * @cfg {Number} aria_valuemax aria-value max
17903 * @cfg {String} label label for the progress bar
17904 * @cfg {String} panel (success | info | warning | danger )
17905 * @cfg {String} role role of the progress bar
17906 * @cfg {String} sr_only text
17910 * Create a new ProgressBar
17911 * @param {Object} config The config object
17914 Roo.bootstrap.ProgressBar = function(config){
17915 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17918 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17922 aria_valuemax : 100,
17928 getAutoCreate : function()
17933 cls: 'progress-bar',
17934 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17946 cfg.role = this.role;
17949 if(this.aria_valuenow){
17950 cfg['aria-valuenow'] = this.aria_valuenow;
17953 if(this.aria_valuemin){
17954 cfg['aria-valuemin'] = this.aria_valuemin;
17957 if(this.aria_valuemax){
17958 cfg['aria-valuemax'] = this.aria_valuemax;
17961 if(this.label && !this.sr_only){
17962 cfg.html = this.label;
17966 cfg.cls += ' progress-bar-' + this.panel;
17972 update : function(aria_valuenow)
17974 this.aria_valuenow = aria_valuenow;
17976 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17991 * @class Roo.bootstrap.TabGroup
17992 * @extends Roo.bootstrap.Column
17993 * Bootstrap Column class
17994 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17995 * @cfg {Boolean} carousel true to make the group behave like a carousel
17996 * @cfg {Boolean} bullets show bullets for the panels
17997 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17998 * @cfg {Number} timer auto slide timer .. default 0 millisecond
17999 * @cfg {Boolean} showarrow (true|false) show arrow default true
18002 * Create a new TabGroup
18003 * @param {Object} config The config object
18006 Roo.bootstrap.TabGroup = function(config){
18007 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18009 this.navId = Roo.id();
18012 Roo.bootstrap.TabGroup.register(this);
18016 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18019 transition : false,
18024 slideOnTouch : false,
18027 getAutoCreate : function()
18029 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18031 cfg.cls += ' tab-content';
18033 if (this.carousel) {
18034 cfg.cls += ' carousel slide';
18037 cls : 'carousel-inner',
18041 if(this.bullets && !Roo.isTouch){
18044 cls : 'carousel-bullets',
18048 if(this.bullets_cls){
18049 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18056 cfg.cn[0].cn.push(bullets);
18059 if(this.showarrow){
18060 cfg.cn[0].cn.push({
18062 class : 'carousel-arrow',
18066 class : 'carousel-prev',
18070 class : 'fa fa-chevron-left'
18076 class : 'carousel-next',
18080 class : 'fa fa-chevron-right'
18093 initEvents: function()
18095 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18096 // this.el.on("touchstart", this.onTouchStart, this);
18099 if(this.autoslide){
18102 this.slideFn = window.setInterval(function() {
18103 _this.showPanelNext();
18107 if(this.showarrow){
18108 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18109 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18115 // onTouchStart : function(e, el, o)
18117 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18121 // this.showPanelNext();
18125 getChildContainer : function()
18127 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18131 * register a Navigation item
18132 * @param {Roo.bootstrap.NavItem} the navitem to add
18134 register : function(item)
18136 this.tabs.push( item);
18137 item.navId = this.navId; // not really needed..
18142 getActivePanel : function()
18145 Roo.each(this.tabs, function(t) {
18155 getPanelByName : function(n)
18158 Roo.each(this.tabs, function(t) {
18159 if (t.tabId == n) {
18167 indexOfPanel : function(p)
18170 Roo.each(this.tabs, function(t,i) {
18171 if (t.tabId == p.tabId) {
18180 * show a specific panel
18181 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18182 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18184 showPanel : function (pan)
18186 if(this.transition || typeof(pan) == 'undefined'){
18187 Roo.log("waiting for the transitionend");
18191 if (typeof(pan) == 'number') {
18192 pan = this.tabs[pan];
18195 if (typeof(pan) == 'string') {
18196 pan = this.getPanelByName(pan);
18199 var cur = this.getActivePanel();
18202 Roo.log('pan or acitve pan is undefined');
18206 if (pan.tabId == this.getActivePanel().tabId) {
18210 if (false === cur.fireEvent('beforedeactivate')) {
18214 if(this.bullets > 0 && !Roo.isTouch){
18215 this.setActiveBullet(this.indexOfPanel(pan));
18218 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18220 this.transition = true;
18221 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18222 var lr = dir == 'next' ? 'left' : 'right';
18223 pan.el.addClass(dir); // or prev
18224 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18225 cur.el.addClass(lr); // or right
18226 pan.el.addClass(lr);
18229 cur.el.on('transitionend', function() {
18230 Roo.log("trans end?");
18232 pan.el.removeClass([lr,dir]);
18233 pan.setActive(true);
18235 cur.el.removeClass([lr]);
18236 cur.setActive(false);
18238 _this.transition = false;
18240 }, this, { single: true } );
18245 cur.setActive(false);
18246 pan.setActive(true);
18251 showPanelNext : function()
18253 var i = this.indexOfPanel(this.getActivePanel());
18255 if (i >= this.tabs.length - 1 && !this.autoslide) {
18259 if (i >= this.tabs.length - 1 && this.autoslide) {
18263 this.showPanel(this.tabs[i+1]);
18266 showPanelPrev : function()
18268 var i = this.indexOfPanel(this.getActivePanel());
18270 if (i < 1 && !this.autoslide) {
18274 if (i < 1 && this.autoslide) {
18275 i = this.tabs.length;
18278 this.showPanel(this.tabs[i-1]);
18282 addBullet: function()
18284 if(!this.bullets || Roo.isTouch){
18287 var ctr = this.el.select('.carousel-bullets',true).first();
18288 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18289 var bullet = ctr.createChild({
18290 cls : 'bullet bullet-' + i
18291 },ctr.dom.lastChild);
18296 bullet.on('click', (function(e, el, o, ii, t){
18298 e.preventDefault();
18300 this.showPanel(ii);
18302 if(this.autoslide && this.slideFn){
18303 clearInterval(this.slideFn);
18304 this.slideFn = window.setInterval(function() {
18305 _this.showPanelNext();
18309 }).createDelegate(this, [i, bullet], true));
18314 setActiveBullet : function(i)
18320 Roo.each(this.el.select('.bullet', true).elements, function(el){
18321 el.removeClass('selected');
18324 var bullet = this.el.select('.bullet-' + i, true).first();
18330 bullet.addClass('selected');
18341 Roo.apply(Roo.bootstrap.TabGroup, {
18345 * register a Navigation Group
18346 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18348 register : function(navgrp)
18350 this.groups[navgrp.navId] = navgrp;
18354 * fetch a Navigation Group based on the navigation ID
18355 * if one does not exist , it will get created.
18356 * @param {string} the navgroup to add
18357 * @returns {Roo.bootstrap.NavGroup} the navgroup
18359 get: function(navId) {
18360 if (typeof(this.groups[navId]) == 'undefined') {
18361 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18363 return this.groups[navId] ;
18378 * @class Roo.bootstrap.TabPanel
18379 * @extends Roo.bootstrap.Component
18380 * Bootstrap TabPanel class
18381 * @cfg {Boolean} active panel active
18382 * @cfg {String} html panel content
18383 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18384 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18385 * @cfg {String} href click to link..
18389 * Create a new TabPanel
18390 * @param {Object} config The config object
18393 Roo.bootstrap.TabPanel = function(config){
18394 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18398 * Fires when the active status changes
18399 * @param {Roo.bootstrap.TabPanel} this
18400 * @param {Boolean} state the new state
18405 * @event beforedeactivate
18406 * Fires before a tab is de-activated - can be used to do validation on a form.
18407 * @param {Roo.bootstrap.TabPanel} this
18408 * @return {Boolean} false if there is an error
18411 'beforedeactivate': true
18414 this.tabId = this.tabId || Roo.id();
18418 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18426 getAutoCreate : function(){
18429 // item is needed for carousel - not sure if it has any effect otherwise
18430 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18431 html: this.html || ''
18435 cfg.cls += ' active';
18439 cfg.tabId = this.tabId;
18446 initEvents: function()
18448 var p = this.parent();
18450 this.navId = this.navId || p.navId;
18452 if (typeof(this.navId) != 'undefined') {
18453 // not really needed.. but just in case.. parent should be a NavGroup.
18454 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18458 var i = tg.tabs.length - 1;
18460 if(this.active && tg.bullets > 0 && i < tg.bullets){
18461 tg.setActiveBullet(i);
18465 this.el.on('click', this.onClick, this);
18468 this.el.on("touchstart", this.onTouchStart, this);
18469 this.el.on("touchmove", this.onTouchMove, this);
18470 this.el.on("touchend", this.onTouchEnd, this);
18475 onRender : function(ct, position)
18477 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18480 setActive : function(state)
18482 Roo.log("panel - set active " + this.tabId + "=" + state);
18484 this.active = state;
18486 this.el.removeClass('active');
18488 } else if (!this.el.hasClass('active')) {
18489 this.el.addClass('active');
18492 this.fireEvent('changed', this, state);
18495 onClick : function(e)
18497 e.preventDefault();
18499 if(!this.href.length){
18503 window.location.href = this.href;
18512 onTouchStart : function(e)
18514 this.swiping = false;
18516 this.startX = e.browserEvent.touches[0].clientX;
18517 this.startY = e.browserEvent.touches[0].clientY;
18520 onTouchMove : function(e)
18522 this.swiping = true;
18524 this.endX = e.browserEvent.touches[0].clientX;
18525 this.endY = e.browserEvent.touches[0].clientY;
18528 onTouchEnd : function(e)
18535 var tabGroup = this.parent();
18537 if(this.endX > this.startX){ // swiping right
18538 tabGroup.showPanelPrev();
18542 if(this.startX > this.endX){ // swiping left
18543 tabGroup.showPanelNext();
18562 * @class Roo.bootstrap.DateField
18563 * @extends Roo.bootstrap.Input
18564 * Bootstrap DateField class
18565 * @cfg {Number} weekStart default 0
18566 * @cfg {String} viewMode default empty, (months|years)
18567 * @cfg {String} minViewMode default empty, (months|years)
18568 * @cfg {Number} startDate default -Infinity
18569 * @cfg {Number} endDate default Infinity
18570 * @cfg {Boolean} todayHighlight default false
18571 * @cfg {Boolean} todayBtn default false
18572 * @cfg {Boolean} calendarWeeks default false
18573 * @cfg {Object} daysOfWeekDisabled default empty
18574 * @cfg {Boolean} singleMode default false (true | false)
18576 * @cfg {Boolean} keyboardNavigation default true
18577 * @cfg {String} language default en
18580 * Create a new DateField
18581 * @param {Object} config The config object
18584 Roo.bootstrap.DateField = function(config){
18585 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18589 * Fires when this field show.
18590 * @param {Roo.bootstrap.DateField} this
18591 * @param {Mixed} date The date value
18596 * Fires when this field hide.
18597 * @param {Roo.bootstrap.DateField} this
18598 * @param {Mixed} date The date value
18603 * Fires when select a date.
18604 * @param {Roo.bootstrap.DateField} this
18605 * @param {Mixed} date The date value
18609 * @event beforeselect
18610 * Fires when before select a date.
18611 * @param {Roo.bootstrap.DateField} this
18612 * @param {Mixed} date The date value
18614 beforeselect : true
18618 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18621 * @cfg {String} format
18622 * The default date format string which can be overriden for localization support. The format must be
18623 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18627 * @cfg {String} altFormats
18628 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18629 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18631 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18639 todayHighlight : false,
18645 keyboardNavigation: true,
18647 calendarWeeks: false,
18649 startDate: -Infinity,
18653 daysOfWeekDisabled: [],
18657 singleMode : false,
18659 UTCDate: function()
18661 return new Date(Date.UTC.apply(Date, arguments));
18664 UTCToday: function()
18666 var today = new Date();
18667 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18670 getDate: function() {
18671 var d = this.getUTCDate();
18672 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18675 getUTCDate: function() {
18679 setDate: function(d) {
18680 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18683 setUTCDate: function(d) {
18685 this.setValue(this.formatDate(this.date));
18688 onRender: function(ct, position)
18691 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18693 this.language = this.language || 'en';
18694 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18695 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18697 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18698 this.format = this.format || 'm/d/y';
18699 this.isInline = false;
18700 this.isInput = true;
18701 this.component = this.el.select('.add-on', true).first() || false;
18702 this.component = (this.component && this.component.length === 0) ? false : this.component;
18703 this.hasInput = this.component && this.inputEl().length;
18705 if (typeof(this.minViewMode === 'string')) {
18706 switch (this.minViewMode) {
18708 this.minViewMode = 1;
18711 this.minViewMode = 2;
18714 this.minViewMode = 0;
18719 if (typeof(this.viewMode === 'string')) {
18720 switch (this.viewMode) {
18733 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18735 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18737 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18739 this.picker().on('mousedown', this.onMousedown, this);
18740 this.picker().on('click', this.onClick, this);
18742 this.picker().addClass('datepicker-dropdown');
18744 this.startViewMode = this.viewMode;
18746 if(this.singleMode){
18747 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18748 v.setVisibilityMode(Roo.Element.DISPLAY);
18752 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18753 v.setStyle('width', '189px');
18757 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18758 if(!this.calendarWeeks){
18763 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18764 v.attr('colspan', function(i, val){
18765 return parseInt(val) + 1;
18770 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18772 this.setStartDate(this.startDate);
18773 this.setEndDate(this.endDate);
18775 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18782 if(this.isInline) {
18787 picker : function()
18789 return this.pickerEl;
18790 // return this.el.select('.datepicker', true).first();
18793 fillDow: function()
18795 var dowCnt = this.weekStart;
18804 if(this.calendarWeeks){
18812 while (dowCnt < this.weekStart + 7) {
18816 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18820 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18823 fillMonths: function()
18826 var months = this.picker().select('>.datepicker-months td', true).first();
18828 months.dom.innerHTML = '';
18834 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18837 months.createChild(month);
18844 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;
18846 if (this.date < this.startDate) {
18847 this.viewDate = new Date(this.startDate);
18848 } else if (this.date > this.endDate) {
18849 this.viewDate = new Date(this.endDate);
18851 this.viewDate = new Date(this.date);
18859 var d = new Date(this.viewDate),
18860 year = d.getUTCFullYear(),
18861 month = d.getUTCMonth(),
18862 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18863 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18864 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18865 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18866 currentDate = this.date && this.date.valueOf(),
18867 today = this.UTCToday();
18869 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18871 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18873 // this.picker.select('>tfoot th.today').
18874 // .text(dates[this.language].today)
18875 // .toggle(this.todayBtn !== false);
18877 this.updateNavArrows();
18880 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18882 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18884 prevMonth.setUTCDate(day);
18886 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18888 var nextMonth = new Date(prevMonth);
18890 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18892 nextMonth = nextMonth.valueOf();
18894 var fillMonths = false;
18896 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18898 while(prevMonth.valueOf() <= nextMonth) {
18901 if (prevMonth.getUTCDay() === this.weekStart) {
18903 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18911 if(this.calendarWeeks){
18912 // ISO 8601: First week contains first thursday.
18913 // ISO also states week starts on Monday, but we can be more abstract here.
18915 // Start of current week: based on weekstart/current date
18916 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18917 // Thursday of this week
18918 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18919 // First Thursday of year, year from thursday
18920 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18921 // Calendar week: ms between thursdays, div ms per day, div 7 days
18922 calWeek = (th - yth) / 864e5 / 7 + 1;
18924 fillMonths.cn.push({
18932 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18934 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18937 if (this.todayHighlight &&
18938 prevMonth.getUTCFullYear() == today.getFullYear() &&
18939 prevMonth.getUTCMonth() == today.getMonth() &&
18940 prevMonth.getUTCDate() == today.getDate()) {
18941 clsName += ' today';
18944 if (currentDate && prevMonth.valueOf() === currentDate) {
18945 clsName += ' active';
18948 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18949 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18950 clsName += ' disabled';
18953 fillMonths.cn.push({
18955 cls: 'day ' + clsName,
18956 html: prevMonth.getDate()
18959 prevMonth.setDate(prevMonth.getDate()+1);
18962 var currentYear = this.date && this.date.getUTCFullYear();
18963 var currentMonth = this.date && this.date.getUTCMonth();
18965 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18967 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18968 v.removeClass('active');
18970 if(currentYear === year && k === currentMonth){
18971 v.addClass('active');
18974 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18975 v.addClass('disabled');
18981 year = parseInt(year/10, 10) * 10;
18983 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18985 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18988 for (var i = -1; i < 11; i++) {
18989 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18991 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18999 showMode: function(dir)
19002 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19005 Roo.each(this.picker().select('>div',true).elements, function(v){
19006 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19009 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19014 if(this.isInline) {
19018 this.picker().removeClass(['bottom', 'top']);
19020 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19022 * place to the top of element!
19026 this.picker().addClass('top');
19027 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19032 this.picker().addClass('bottom');
19034 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19037 parseDate : function(value)
19039 if(!value || value instanceof Date){
19042 var v = Date.parseDate(value, this.format);
19043 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19044 v = Date.parseDate(value, 'Y-m-d');
19046 if(!v && this.altFormats){
19047 if(!this.altFormatsArray){
19048 this.altFormatsArray = this.altFormats.split("|");
19050 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19051 v = Date.parseDate(value, this.altFormatsArray[i]);
19057 formatDate : function(date, fmt)
19059 return (!date || !(date instanceof Date)) ?
19060 date : date.dateFormat(fmt || this.format);
19063 onFocus : function()
19065 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19069 onBlur : function()
19071 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19073 var d = this.inputEl().getValue();
19080 showPopup : function()
19082 this.picker().show();
19086 this.fireEvent('showpopup', this, this.date);
19089 hidePopup : function()
19091 if(this.isInline) {
19094 this.picker().hide();
19095 this.viewMode = this.startViewMode;
19098 this.fireEvent('hidepopup', this, this.date);
19102 onMousedown: function(e)
19104 e.stopPropagation();
19105 e.preventDefault();
19110 Roo.bootstrap.DateField.superclass.keyup.call(this);
19114 setValue: function(v)
19116 if(this.fireEvent('beforeselect', this, v) !== false){
19117 var d = new Date(this.parseDate(v) ).clearTime();
19119 if(isNaN(d.getTime())){
19120 this.date = this.viewDate = '';
19121 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19125 v = this.formatDate(d);
19127 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19129 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19133 this.fireEvent('select', this, this.date);
19137 getValue: function()
19139 return this.formatDate(this.date);
19142 fireKey: function(e)
19144 if (!this.picker().isVisible()){
19145 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19151 var dateChanged = false,
19153 newDate, newViewDate;
19158 e.preventDefault();
19162 if (!this.keyboardNavigation) {
19165 dir = e.keyCode == 37 ? -1 : 1;
19168 newDate = this.moveYear(this.date, dir);
19169 newViewDate = this.moveYear(this.viewDate, dir);
19170 } else if (e.shiftKey){
19171 newDate = this.moveMonth(this.date, dir);
19172 newViewDate = this.moveMonth(this.viewDate, dir);
19174 newDate = new Date(this.date);
19175 newDate.setUTCDate(this.date.getUTCDate() + dir);
19176 newViewDate = new Date(this.viewDate);
19177 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19179 if (this.dateWithinRange(newDate)){
19180 this.date = newDate;
19181 this.viewDate = newViewDate;
19182 this.setValue(this.formatDate(this.date));
19184 e.preventDefault();
19185 dateChanged = true;
19190 if (!this.keyboardNavigation) {
19193 dir = e.keyCode == 38 ? -1 : 1;
19195 newDate = this.moveYear(this.date, dir);
19196 newViewDate = this.moveYear(this.viewDate, dir);
19197 } else if (e.shiftKey){
19198 newDate = this.moveMonth(this.date, dir);
19199 newViewDate = this.moveMonth(this.viewDate, dir);
19201 newDate = new Date(this.date);
19202 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19203 newViewDate = new Date(this.viewDate);
19204 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19206 if (this.dateWithinRange(newDate)){
19207 this.date = newDate;
19208 this.viewDate = newViewDate;
19209 this.setValue(this.formatDate(this.date));
19211 e.preventDefault();
19212 dateChanged = true;
19216 this.setValue(this.formatDate(this.date));
19218 e.preventDefault();
19221 this.setValue(this.formatDate(this.date));
19235 onClick: function(e)
19237 e.stopPropagation();
19238 e.preventDefault();
19240 var target = e.getTarget();
19242 if(target.nodeName.toLowerCase() === 'i'){
19243 target = Roo.get(target).dom.parentNode;
19246 var nodeName = target.nodeName;
19247 var className = target.className;
19248 var html = target.innerHTML;
19249 //Roo.log(nodeName);
19251 switch(nodeName.toLowerCase()) {
19253 switch(className) {
19259 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19260 switch(this.viewMode){
19262 this.viewDate = this.moveMonth(this.viewDate, dir);
19266 this.viewDate = this.moveYear(this.viewDate, dir);
19272 var date = new Date();
19273 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19275 this.setValue(this.formatDate(this.date));
19282 if (className.indexOf('disabled') < 0) {
19283 this.viewDate.setUTCDate(1);
19284 if (className.indexOf('month') > -1) {
19285 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19287 var year = parseInt(html, 10) || 0;
19288 this.viewDate.setUTCFullYear(year);
19292 if(this.singleMode){
19293 this.setValue(this.formatDate(this.viewDate));
19304 //Roo.log(className);
19305 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19306 var day = parseInt(html, 10) || 1;
19307 var year = this.viewDate.getUTCFullYear(),
19308 month = this.viewDate.getUTCMonth();
19310 if (className.indexOf('old') > -1) {
19317 } else if (className.indexOf('new') > -1) {
19325 //Roo.log([year,month,day]);
19326 this.date = this.UTCDate(year, month, day,0,0,0,0);
19327 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19329 //Roo.log(this.formatDate(this.date));
19330 this.setValue(this.formatDate(this.date));
19337 setStartDate: function(startDate)
19339 this.startDate = startDate || -Infinity;
19340 if (this.startDate !== -Infinity) {
19341 this.startDate = this.parseDate(this.startDate);
19344 this.updateNavArrows();
19347 setEndDate: function(endDate)
19349 this.endDate = endDate || Infinity;
19350 if (this.endDate !== Infinity) {
19351 this.endDate = this.parseDate(this.endDate);
19354 this.updateNavArrows();
19357 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19359 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19360 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19361 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19363 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19364 return parseInt(d, 10);
19367 this.updateNavArrows();
19370 updateNavArrows: function()
19372 if(this.singleMode){
19376 var d = new Date(this.viewDate),
19377 year = d.getUTCFullYear(),
19378 month = d.getUTCMonth();
19380 Roo.each(this.picker().select('.prev', true).elements, function(v){
19382 switch (this.viewMode) {
19385 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19391 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19398 Roo.each(this.picker().select('.next', true).elements, function(v){
19400 switch (this.viewMode) {
19403 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19409 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19417 moveMonth: function(date, dir)
19422 var new_date = new Date(date.valueOf()),
19423 day = new_date.getUTCDate(),
19424 month = new_date.getUTCMonth(),
19425 mag = Math.abs(dir),
19427 dir = dir > 0 ? 1 : -1;
19430 // If going back one month, make sure month is not current month
19431 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19433 return new_date.getUTCMonth() == month;
19435 // If going forward one month, make sure month is as expected
19436 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19438 return new_date.getUTCMonth() != new_month;
19440 new_month = month + dir;
19441 new_date.setUTCMonth(new_month);
19442 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19443 if (new_month < 0 || new_month > 11) {
19444 new_month = (new_month + 12) % 12;
19447 // For magnitudes >1, move one month at a time...
19448 for (var i=0; i<mag; i++) {
19449 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19450 new_date = this.moveMonth(new_date, dir);
19452 // ...then reset the day, keeping it in the new month
19453 new_month = new_date.getUTCMonth();
19454 new_date.setUTCDate(day);
19456 return new_month != new_date.getUTCMonth();
19459 // Common date-resetting loop -- if date is beyond end of month, make it
19462 new_date.setUTCDate(--day);
19463 new_date.setUTCMonth(new_month);
19468 moveYear: function(date, dir)
19470 return this.moveMonth(date, dir*12);
19473 dateWithinRange: function(date)
19475 return date >= this.startDate && date <= this.endDate;
19481 this.picker().remove();
19484 validateValue : function(value)
19486 if(this.getVisibilityEl().hasClass('hidden')){
19490 if(value.length < 1) {
19491 if(this.allowBlank){
19497 if(value.length < this.minLength){
19500 if(value.length > this.maxLength){
19504 var vt = Roo.form.VTypes;
19505 if(!vt[this.vtype](value, this)){
19509 if(typeof this.validator == "function"){
19510 var msg = this.validator(value);
19516 if(this.regex && !this.regex.test(value)){
19520 if(typeof(this.parseDate(value)) == 'undefined'){
19524 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19528 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19538 this.date = this.viewDate = '';
19540 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19545 Roo.apply(Roo.bootstrap.DateField, {
19556 html: '<i class="fa fa-arrow-left"/>'
19566 html: '<i class="fa fa-arrow-right"/>'
19608 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19609 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19610 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19611 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19612 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19625 navFnc: 'FullYear',
19630 navFnc: 'FullYear',
19635 Roo.apply(Roo.bootstrap.DateField, {
19639 cls: 'datepicker dropdown-menu roo-dynamic',
19643 cls: 'datepicker-days',
19647 cls: 'table-condensed',
19649 Roo.bootstrap.DateField.head,
19653 Roo.bootstrap.DateField.footer
19660 cls: 'datepicker-months',
19664 cls: 'table-condensed',
19666 Roo.bootstrap.DateField.head,
19667 Roo.bootstrap.DateField.content,
19668 Roo.bootstrap.DateField.footer
19675 cls: 'datepicker-years',
19679 cls: 'table-condensed',
19681 Roo.bootstrap.DateField.head,
19682 Roo.bootstrap.DateField.content,
19683 Roo.bootstrap.DateField.footer
19702 * @class Roo.bootstrap.TimeField
19703 * @extends Roo.bootstrap.Input
19704 * Bootstrap DateField class
19708 * Create a new TimeField
19709 * @param {Object} config The config object
19712 Roo.bootstrap.TimeField = function(config){
19713 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19717 * Fires when this field show.
19718 * @param {Roo.bootstrap.DateField} thisthis
19719 * @param {Mixed} date The date value
19724 * Fires when this field hide.
19725 * @param {Roo.bootstrap.DateField} this
19726 * @param {Mixed} date The date value
19731 * Fires when select a date.
19732 * @param {Roo.bootstrap.DateField} this
19733 * @param {Mixed} date The date value
19739 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19742 * @cfg {String} format
19743 * The default time format string which can be overriden for localization support. The format must be
19744 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19748 onRender: function(ct, position)
19751 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19753 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19755 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19757 this.pop = this.picker().select('>.datepicker-time',true).first();
19758 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19760 this.picker().on('mousedown', this.onMousedown, this);
19761 this.picker().on('click', this.onClick, this);
19763 this.picker().addClass('datepicker-dropdown');
19768 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19769 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19770 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19771 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19772 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19773 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19777 fireKey: function(e){
19778 if (!this.picker().isVisible()){
19779 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19785 e.preventDefault();
19793 this.onTogglePeriod();
19796 this.onIncrementMinutes();
19799 this.onDecrementMinutes();
19808 onClick: function(e) {
19809 e.stopPropagation();
19810 e.preventDefault();
19813 picker : function()
19815 return this.el.select('.datepicker', true).first();
19818 fillTime: function()
19820 var time = this.pop.select('tbody', true).first();
19822 time.dom.innerHTML = '';
19837 cls: 'hours-up glyphicon glyphicon-chevron-up'
19857 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19878 cls: 'timepicker-hour',
19893 cls: 'timepicker-minute',
19908 cls: 'btn btn-primary period',
19930 cls: 'hours-down glyphicon glyphicon-chevron-down'
19950 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19968 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19975 var hours = this.time.getHours();
19976 var minutes = this.time.getMinutes();
19989 hours = hours - 12;
19993 hours = '0' + hours;
19997 minutes = '0' + minutes;
20000 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20001 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20002 this.pop.select('button', true).first().dom.innerHTML = period;
20008 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20010 var cls = ['bottom'];
20012 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20019 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20024 this.picker().addClass(cls.join('-'));
20028 Roo.each(cls, function(c){
20030 _this.picker().setTop(_this.inputEl().getHeight());
20034 _this.picker().setTop(0 - _this.picker().getHeight());
20039 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20043 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20050 onFocus : function()
20052 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20056 onBlur : function()
20058 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20064 this.picker().show();
20069 this.fireEvent('show', this, this.date);
20074 this.picker().hide();
20077 this.fireEvent('hide', this, this.date);
20080 setTime : function()
20083 this.setValue(this.time.format(this.format));
20085 this.fireEvent('select', this, this.date);
20090 onMousedown: function(e){
20091 e.stopPropagation();
20092 e.preventDefault();
20095 onIncrementHours: function()
20097 Roo.log('onIncrementHours');
20098 this.time = this.time.add(Date.HOUR, 1);
20103 onDecrementHours: function()
20105 Roo.log('onDecrementHours');
20106 this.time = this.time.add(Date.HOUR, -1);
20110 onIncrementMinutes: function()
20112 Roo.log('onIncrementMinutes');
20113 this.time = this.time.add(Date.MINUTE, 1);
20117 onDecrementMinutes: function()
20119 Roo.log('onDecrementMinutes');
20120 this.time = this.time.add(Date.MINUTE, -1);
20124 onTogglePeriod: function()
20126 Roo.log('onTogglePeriod');
20127 this.time = this.time.add(Date.HOUR, 12);
20134 Roo.apply(Roo.bootstrap.TimeField, {
20164 cls: 'btn btn-info ok',
20176 Roo.apply(Roo.bootstrap.TimeField, {
20180 cls: 'datepicker dropdown-menu',
20184 cls: 'datepicker-time',
20188 cls: 'table-condensed',
20190 Roo.bootstrap.TimeField.content,
20191 Roo.bootstrap.TimeField.footer
20210 * @class Roo.bootstrap.MonthField
20211 * @extends Roo.bootstrap.Input
20212 * Bootstrap MonthField class
20214 * @cfg {String} language default en
20217 * Create a new MonthField
20218 * @param {Object} config The config object
20221 Roo.bootstrap.MonthField = function(config){
20222 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20227 * Fires when this field show.
20228 * @param {Roo.bootstrap.MonthField} this
20229 * @param {Mixed} date The date value
20234 * Fires when this field hide.
20235 * @param {Roo.bootstrap.MonthField} this
20236 * @param {Mixed} date The date value
20241 * Fires when select a date.
20242 * @param {Roo.bootstrap.MonthField} this
20243 * @param {String} oldvalue The old value
20244 * @param {String} newvalue The new value
20250 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20252 onRender: function(ct, position)
20255 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20257 this.language = this.language || 'en';
20258 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20259 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20261 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20262 this.isInline = false;
20263 this.isInput = true;
20264 this.component = this.el.select('.add-on', true).first() || false;
20265 this.component = (this.component && this.component.length === 0) ? false : this.component;
20266 this.hasInput = this.component && this.inputEL().length;
20268 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20270 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20272 this.picker().on('mousedown', this.onMousedown, this);
20273 this.picker().on('click', this.onClick, this);
20275 this.picker().addClass('datepicker-dropdown');
20277 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20278 v.setStyle('width', '189px');
20285 if(this.isInline) {
20291 setValue: function(v, suppressEvent)
20293 var o = this.getValue();
20295 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20299 if(suppressEvent !== true){
20300 this.fireEvent('select', this, o, v);
20305 getValue: function()
20310 onClick: function(e)
20312 e.stopPropagation();
20313 e.preventDefault();
20315 var target = e.getTarget();
20317 if(target.nodeName.toLowerCase() === 'i'){
20318 target = Roo.get(target).dom.parentNode;
20321 var nodeName = target.nodeName;
20322 var className = target.className;
20323 var html = target.innerHTML;
20325 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20329 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20331 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20337 picker : function()
20339 return this.pickerEl;
20342 fillMonths: function()
20345 var months = this.picker().select('>.datepicker-months td', true).first();
20347 months.dom.innerHTML = '';
20353 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20356 months.createChild(month);
20365 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20366 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20369 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20370 e.removeClass('active');
20372 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20373 e.addClass('active');
20380 if(this.isInline) {
20384 this.picker().removeClass(['bottom', 'top']);
20386 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20388 * place to the top of element!
20392 this.picker().addClass('top');
20393 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20398 this.picker().addClass('bottom');
20400 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20403 onFocus : function()
20405 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20409 onBlur : function()
20411 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20413 var d = this.inputEl().getValue();
20422 this.picker().show();
20423 this.picker().select('>.datepicker-months', true).first().show();
20427 this.fireEvent('show', this, this.date);
20432 if(this.isInline) {
20435 this.picker().hide();
20436 this.fireEvent('hide', this, this.date);
20440 onMousedown: function(e)
20442 e.stopPropagation();
20443 e.preventDefault();
20448 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20452 fireKey: function(e)
20454 if (!this.picker().isVisible()){
20455 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20466 e.preventDefault();
20470 dir = e.keyCode == 37 ? -1 : 1;
20472 this.vIndex = this.vIndex + dir;
20474 if(this.vIndex < 0){
20478 if(this.vIndex > 11){
20482 if(isNaN(this.vIndex)){
20486 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20492 dir = e.keyCode == 38 ? -1 : 1;
20494 this.vIndex = this.vIndex + dir * 4;
20496 if(this.vIndex < 0){
20500 if(this.vIndex > 11){
20504 if(isNaN(this.vIndex)){
20508 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20513 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20514 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20518 e.preventDefault();
20521 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20522 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20538 this.picker().remove();
20543 Roo.apply(Roo.bootstrap.MonthField, {
20562 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20563 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20568 Roo.apply(Roo.bootstrap.MonthField, {
20572 cls: 'datepicker dropdown-menu roo-dynamic',
20576 cls: 'datepicker-months',
20580 cls: 'table-condensed',
20582 Roo.bootstrap.DateField.content
20602 * @class Roo.bootstrap.CheckBox
20603 * @extends Roo.bootstrap.Input
20604 * Bootstrap CheckBox class
20606 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20607 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20608 * @cfg {String} boxLabel The text that appears beside the checkbox
20609 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20610 * @cfg {Boolean} checked initnal the element
20611 * @cfg {Boolean} inline inline the element (default false)
20612 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20613 * @cfg {String} tooltip label tooltip
20616 * Create a new CheckBox
20617 * @param {Object} config The config object
20620 Roo.bootstrap.CheckBox = function(config){
20621 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20626 * Fires when the element is checked or unchecked.
20627 * @param {Roo.bootstrap.CheckBox} this This input
20628 * @param {Boolean} checked The new checked value
20633 * Fires when the element is click.
20634 * @param {Roo.bootstrap.CheckBox} this This input
20641 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20643 inputType: 'checkbox',
20652 getAutoCreate : function()
20654 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20660 cfg.cls = 'form-group ' + this.inputType; //input-group
20663 cfg.cls += ' ' + this.inputType + '-inline';
20669 type : this.inputType,
20670 value : this.inputValue,
20671 cls : 'roo-' + this.inputType, //'form-box',
20672 placeholder : this.placeholder || ''
20676 if(this.inputType != 'radio'){
20680 cls : 'roo-hidden-value',
20681 value : this.checked ? this.inputValue : this.valueOff
20686 if (this.weight) { // Validity check?
20687 cfg.cls += " " + this.inputType + "-" + this.weight;
20690 if (this.disabled) {
20691 input.disabled=true;
20695 input.checked = this.checked;
20700 input.name = this.name;
20702 if(this.inputType != 'radio'){
20703 hidden.name = this.name;
20704 input.name = '_hidden_' + this.name;
20709 input.cls += ' input-' + this.size;
20714 ['xs','sm','md','lg'].map(function(size){
20715 if (settings[size]) {
20716 cfg.cls += ' col-' + size + '-' + settings[size];
20720 var inputblock = input;
20722 if (this.before || this.after) {
20725 cls : 'input-group',
20730 inputblock.cn.push({
20732 cls : 'input-group-addon',
20737 inputblock.cn.push(input);
20739 if(this.inputType != 'radio'){
20740 inputblock.cn.push(hidden);
20744 inputblock.cn.push({
20746 cls : 'input-group-addon',
20753 if (align ==='left' && this.fieldLabel.length) {
20754 // Roo.log("left and has label");
20759 cls : 'control-label',
20760 html : this.fieldLabel
20770 if(this.labelWidth > 12){
20771 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20774 if(this.labelWidth < 13 && this.labelmd == 0){
20775 this.labelmd = this.labelWidth;
20778 if(this.labellg > 0){
20779 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20780 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20783 if(this.labelmd > 0){
20784 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20785 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20788 if(this.labelsm > 0){
20789 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20790 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20793 if(this.labelxs > 0){
20794 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20795 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20798 } else if ( this.fieldLabel.length) {
20799 // Roo.log(" label");
20803 tag: this.boxLabel ? 'span' : 'label',
20805 cls: 'control-label box-input-label',
20806 //cls : 'input-group-addon',
20807 html : this.fieldLabel
20816 // Roo.log(" no label && no align");
20817 cfg.cn = [ inputblock ] ;
20823 var boxLabelCfg = {
20825 //'for': id, // box label is handled by onclick - so no for...
20827 html: this.boxLabel
20831 boxLabelCfg.tooltip = this.tooltip;
20834 cfg.cn.push(boxLabelCfg);
20837 if(this.inputType != 'radio'){
20838 cfg.cn.push(hidden);
20846 * return the real input element.
20848 inputEl: function ()
20850 return this.el.select('input.roo-' + this.inputType,true).first();
20852 hiddenEl: function ()
20854 return this.el.select('input.roo-hidden-value',true).first();
20857 labelEl: function()
20859 return this.el.select('label.control-label',true).first();
20861 /* depricated... */
20865 return this.labelEl();
20868 boxLabelEl: function()
20870 return this.el.select('label.box-label',true).first();
20873 initEvents : function()
20875 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20877 this.inputEl().on('click', this.onClick, this);
20879 if (this.boxLabel) {
20880 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20883 this.startValue = this.getValue();
20886 Roo.bootstrap.CheckBox.register(this);
20890 onClick : function(e)
20892 if(this.fireEvent('click', this, e) !== false){
20893 this.setChecked(!this.checked);
20898 setChecked : function(state,suppressEvent)
20900 this.startValue = this.getValue();
20902 if(this.inputType == 'radio'){
20904 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20905 e.dom.checked = false;
20908 this.inputEl().dom.checked = true;
20910 this.inputEl().dom.value = this.inputValue;
20912 if(suppressEvent !== true){
20913 this.fireEvent('check', this, true);
20921 this.checked = state;
20923 this.inputEl().dom.checked = state;
20926 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20928 if(suppressEvent !== true){
20929 this.fireEvent('check', this, state);
20935 getValue : function()
20937 if(this.inputType == 'radio'){
20938 return this.getGroupValue();
20941 return this.hiddenEl().dom.value;
20945 getGroupValue : function()
20947 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20951 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20954 setValue : function(v,suppressEvent)
20956 if(this.inputType == 'radio'){
20957 this.setGroupValue(v, suppressEvent);
20961 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20966 setGroupValue : function(v, suppressEvent)
20968 this.startValue = this.getValue();
20970 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20971 e.dom.checked = false;
20973 if(e.dom.value == v){
20974 e.dom.checked = true;
20978 if(suppressEvent !== true){
20979 this.fireEvent('check', this, true);
20987 validate : function()
20989 if(this.getVisibilityEl().hasClass('hidden')){
20995 (this.inputType == 'radio' && this.validateRadio()) ||
20996 (this.inputType == 'checkbox' && this.validateCheckbox())
21002 this.markInvalid();
21006 validateRadio : function()
21008 if(this.getVisibilityEl().hasClass('hidden')){
21012 if(this.allowBlank){
21018 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21019 if(!e.dom.checked){
21031 validateCheckbox : function()
21034 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21035 //return (this.getValue() == this.inputValue) ? true : false;
21038 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21046 for(var i in group){
21047 if(group[i].el.isVisible(true)){
21055 for(var i in group){
21060 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21067 * Mark this field as valid
21069 markValid : function()
21073 this.fireEvent('valid', this);
21075 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21078 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21085 if(this.inputType == 'radio'){
21086 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21087 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21088 e.findParent('.form-group', false, true).addClass(_this.validClass);
21095 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21096 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21100 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21106 for(var i in group){
21107 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21108 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21113 * Mark this field as invalid
21114 * @param {String} msg The validation message
21116 markInvalid : function(msg)
21118 if(this.allowBlank){
21124 this.fireEvent('invalid', this, msg);
21126 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21129 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21133 label.markInvalid();
21136 if(this.inputType == 'radio'){
21137 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21138 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21139 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21146 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21147 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21151 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21157 for(var i in group){
21158 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21159 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21164 clearInvalid : function()
21166 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21168 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21170 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21172 if (label && label.iconEl) {
21173 label.iconEl.removeClass(label.validClass);
21174 label.iconEl.removeClass(label.invalidClass);
21178 disable : function()
21180 if(this.inputType != 'radio'){
21181 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21188 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21189 _this.getActionEl().addClass(this.disabledClass);
21190 e.dom.disabled = true;
21194 this.disabled = true;
21195 this.fireEvent("disable", this);
21199 enable : function()
21201 if(this.inputType != 'radio'){
21202 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21209 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21210 _this.getActionEl().removeClass(this.disabledClass);
21211 e.dom.disabled = false;
21215 this.disabled = false;
21216 this.fireEvent("enable", this);
21220 setBoxLabel : function(v)
21225 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21231 Roo.apply(Roo.bootstrap.CheckBox, {
21236 * register a CheckBox Group
21237 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21239 register : function(checkbox)
21241 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21242 this.groups[checkbox.groupId] = {};
21245 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21249 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21253 * fetch a CheckBox Group based on the group ID
21254 * @param {string} the group ID
21255 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21257 get: function(groupId) {
21258 if (typeof(this.groups[groupId]) == 'undefined') {
21262 return this.groups[groupId] ;
21275 * @class Roo.bootstrap.Radio
21276 * @extends Roo.bootstrap.Component
21277 * Bootstrap Radio class
21278 * @cfg {String} boxLabel - the label associated
21279 * @cfg {String} value - the value of radio
21282 * Create a new Radio
21283 * @param {Object} config The config object
21285 Roo.bootstrap.Radio = function(config){
21286 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21290 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21296 getAutoCreate : function()
21300 cls : 'form-group radio',
21305 html : this.boxLabel
21313 initEvents : function()
21315 this.parent().register(this);
21317 this.el.on('click', this.onClick, this);
21321 onClick : function(e)
21323 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21324 this.setChecked(true);
21328 setChecked : function(state, suppressEvent)
21330 this.parent().setValue(this.value, suppressEvent);
21334 setBoxLabel : function(v)
21339 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21354 * @class Roo.bootstrap.SecurePass
21355 * @extends Roo.bootstrap.Input
21356 * Bootstrap SecurePass class
21360 * Create a new SecurePass
21361 * @param {Object} config The config object
21364 Roo.bootstrap.SecurePass = function (config) {
21365 // these go here, so the translation tool can replace them..
21367 PwdEmpty: "Please type a password, and then retype it to confirm.",
21368 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21369 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21370 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21371 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21372 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21373 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21374 TooWeak: "Your password is Too Weak."
21376 this.meterLabel = "Password strength:";
21377 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21378 this.meterClass = [
21379 "roo-password-meter-tooweak",
21380 "roo-password-meter-weak",
21381 "roo-password-meter-medium",
21382 "roo-password-meter-strong",
21383 "roo-password-meter-grey"
21388 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21391 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21393 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21395 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21396 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21397 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21398 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21399 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21400 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21401 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21411 * @cfg {String/Object} Label for the strength meter (defaults to
21412 * 'Password strength:')
21417 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21418 * ['Weak', 'Medium', 'Strong'])
21421 pwdStrengths: false,
21434 initEvents: function ()
21436 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21438 if (this.el.is('input[type=password]') && Roo.isSafari) {
21439 this.el.on('keydown', this.SafariOnKeyDown, this);
21442 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21445 onRender: function (ct, position)
21447 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21448 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21449 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21451 this.trigger.createChild({
21456 cls: 'roo-password-meter-grey col-xs-12',
21459 //width: this.meterWidth + 'px'
21463 cls: 'roo-password-meter-text'
21469 if (this.hideTrigger) {
21470 this.trigger.setDisplayed(false);
21472 this.setSize(this.width || '', this.height || '');
21475 onDestroy: function ()
21477 if (this.trigger) {
21478 this.trigger.removeAllListeners();
21479 this.trigger.remove();
21482 this.wrap.remove();
21484 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21487 checkStrength: function ()
21489 var pwd = this.inputEl().getValue();
21490 if (pwd == this._lastPwd) {
21495 if (this.ClientSideStrongPassword(pwd)) {
21497 } else if (this.ClientSideMediumPassword(pwd)) {
21499 } else if (this.ClientSideWeakPassword(pwd)) {
21505 Roo.log('strength1: ' + strength);
21507 //var pm = this.trigger.child('div/div/div').dom;
21508 var pm = this.trigger.child('div/div');
21509 pm.removeClass(this.meterClass);
21510 pm.addClass(this.meterClass[strength]);
21513 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21515 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21517 this._lastPwd = pwd;
21521 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21523 this._lastPwd = '';
21525 var pm = this.trigger.child('div/div');
21526 pm.removeClass(this.meterClass);
21527 pm.addClass('roo-password-meter-grey');
21530 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21533 this.inputEl().dom.type='password';
21536 validateValue: function (value)
21539 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21542 if (value.length == 0) {
21543 if (this.allowBlank) {
21544 this.clearInvalid();
21548 this.markInvalid(this.errors.PwdEmpty);
21549 this.errorMsg = this.errors.PwdEmpty;
21557 if ('[\x21-\x7e]*'.match(value)) {
21558 this.markInvalid(this.errors.PwdBadChar);
21559 this.errorMsg = this.errors.PwdBadChar;
21562 if (value.length < 6) {
21563 this.markInvalid(this.errors.PwdShort);
21564 this.errorMsg = this.errors.PwdShort;
21567 if (value.length > 16) {
21568 this.markInvalid(this.errors.PwdLong);
21569 this.errorMsg = this.errors.PwdLong;
21573 if (this.ClientSideStrongPassword(value)) {
21575 } else if (this.ClientSideMediumPassword(value)) {
21577 } else if (this.ClientSideWeakPassword(value)) {
21584 if (strength < 2) {
21585 //this.markInvalid(this.errors.TooWeak);
21586 this.errorMsg = this.errors.TooWeak;
21591 console.log('strength2: ' + strength);
21593 //var pm = this.trigger.child('div/div/div').dom;
21595 var pm = this.trigger.child('div/div');
21596 pm.removeClass(this.meterClass);
21597 pm.addClass(this.meterClass[strength]);
21599 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21601 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21603 this.errorMsg = '';
21607 CharacterSetChecks: function (type)
21610 this.fResult = false;
21613 isctype: function (character, type)
21616 case this.kCapitalLetter:
21617 if (character >= 'A' && character <= 'Z') {
21622 case this.kSmallLetter:
21623 if (character >= 'a' && character <= 'z') {
21629 if (character >= '0' && character <= '9') {
21634 case this.kPunctuation:
21635 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21646 IsLongEnough: function (pwd, size)
21648 return !(pwd == null || isNaN(size) || pwd.length < size);
21651 SpansEnoughCharacterSets: function (word, nb)
21653 if (!this.IsLongEnough(word, nb))
21658 var characterSetChecks = new Array(
21659 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21660 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21663 for (var index = 0; index < word.length; ++index) {
21664 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21665 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21666 characterSetChecks[nCharSet].fResult = true;
21673 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21674 if (characterSetChecks[nCharSet].fResult) {
21679 if (nCharSets < nb) {
21685 ClientSideStrongPassword: function (pwd)
21687 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21690 ClientSideMediumPassword: function (pwd)
21692 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21695 ClientSideWeakPassword: function (pwd)
21697 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21700 })//<script type="text/javascript">
21703 * Based Ext JS Library 1.1.1
21704 * Copyright(c) 2006-2007, Ext JS, LLC.
21710 * @class Roo.HtmlEditorCore
21711 * @extends Roo.Component
21712 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21714 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21717 Roo.HtmlEditorCore = function(config){
21720 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21725 * @event initialize
21726 * Fires when the editor is fully initialized (including the iframe)
21727 * @param {Roo.HtmlEditorCore} this
21732 * Fires when the editor is first receives the focus. Any insertion must wait
21733 * until after this event.
21734 * @param {Roo.HtmlEditorCore} this
21738 * @event beforesync
21739 * Fires before the textarea is updated with content from the editor iframe. Return false
21740 * to cancel the sync.
21741 * @param {Roo.HtmlEditorCore} this
21742 * @param {String} html
21746 * @event beforepush
21747 * Fires before the iframe editor is updated with content from the textarea. Return false
21748 * to cancel the push.
21749 * @param {Roo.HtmlEditorCore} this
21750 * @param {String} html
21755 * Fires when the textarea is updated with content from the editor iframe.
21756 * @param {Roo.HtmlEditorCore} this
21757 * @param {String} html
21762 * Fires when the iframe editor is updated with content from the textarea.
21763 * @param {Roo.HtmlEditorCore} this
21764 * @param {String} html
21769 * @event editorevent
21770 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21771 * @param {Roo.HtmlEditorCore} this
21777 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21779 // defaults : white / black...
21780 this.applyBlacklists();
21787 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21791 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21797 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21802 * @cfg {Number} height (in pixels)
21806 * @cfg {Number} width (in pixels)
21811 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21814 stylesheets: false,
21819 // private properties
21820 validationEvent : false,
21822 initialized : false,
21824 sourceEditMode : false,
21825 onFocus : Roo.emptyFn,
21827 hideMode:'offsets',
21831 // blacklist + whitelisted elements..
21838 * Protected method that will not generally be called directly. It
21839 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21840 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21842 getDocMarkup : function(){
21846 // inherit styels from page...??
21847 if (this.stylesheets === false) {
21849 Roo.get(document.head).select('style').each(function(node) {
21850 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21853 Roo.get(document.head).select('link').each(function(node) {
21854 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21857 } else if (!this.stylesheets.length) {
21859 st = '<style type="text/css">' +
21860 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21863 st = '<style type="text/css">' +
21868 st += '<style type="text/css">' +
21869 'IMG { cursor: pointer } ' +
21872 var cls = 'roo-htmleditor-body';
21874 if(this.bodyCls.length){
21875 cls += ' ' + this.bodyCls;
21878 return '<html><head>' + st +
21879 //<style type="text/css">' +
21880 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21882 ' </head><body class="' + cls + '"></body></html>';
21886 onRender : function(ct, position)
21889 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21890 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21893 this.el.dom.style.border = '0 none';
21894 this.el.dom.setAttribute('tabIndex', -1);
21895 this.el.addClass('x-hidden hide');
21899 if(Roo.isIE){ // fix IE 1px bogus margin
21900 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21904 this.frameId = Roo.id();
21908 var iframe = this.owner.wrap.createChild({
21910 cls: 'form-control', // bootstrap..
21912 name: this.frameId,
21913 frameBorder : 'no',
21914 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21919 this.iframe = iframe.dom;
21921 this.assignDocWin();
21923 this.doc.designMode = 'on';
21926 this.doc.write(this.getDocMarkup());
21930 var task = { // must defer to wait for browser to be ready
21932 //console.log("run task?" + this.doc.readyState);
21933 this.assignDocWin();
21934 if(this.doc.body || this.doc.readyState == 'complete'){
21936 this.doc.designMode="on";
21940 Roo.TaskMgr.stop(task);
21941 this.initEditor.defer(10, this);
21948 Roo.TaskMgr.start(task);
21953 onResize : function(w, h)
21955 Roo.log('resize: ' +w + ',' + h );
21956 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21960 if(typeof w == 'number'){
21962 this.iframe.style.width = w + 'px';
21964 if(typeof h == 'number'){
21966 this.iframe.style.height = h + 'px';
21968 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21975 * Toggles the editor between standard and source edit mode.
21976 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21978 toggleSourceEdit : function(sourceEditMode){
21980 this.sourceEditMode = sourceEditMode === true;
21982 if(this.sourceEditMode){
21984 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
21987 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21988 //this.iframe.className = '';
21991 //this.setSize(this.owner.wrap.getSize());
21992 //this.fireEvent('editmodechange', this, this.sourceEditMode);
21999 * Protected method that will not generally be called directly. If you need/want
22000 * custom HTML cleanup, this is the method you should override.
22001 * @param {String} html The HTML to be cleaned
22002 * return {String} The cleaned HTML
22004 cleanHtml : function(html){
22005 html = String(html);
22006 if(html.length > 5){
22007 if(Roo.isSafari){ // strip safari nonsense
22008 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22011 if(html == ' '){
22018 * HTML Editor -> Textarea
22019 * Protected method that will not generally be called directly. Syncs the contents
22020 * of the editor iframe with the textarea.
22022 syncValue : function(){
22023 if(this.initialized){
22024 var bd = (this.doc.body || this.doc.documentElement);
22025 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22026 var html = bd.innerHTML;
22028 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22029 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22031 html = '<div style="'+m[0]+'">' + html + '</div>';
22034 html = this.cleanHtml(html);
22035 // fix up the special chars.. normaly like back quotes in word...
22036 // however we do not want to do this with chinese..
22037 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22038 var cc = b.charCodeAt();
22040 (cc >= 0x4E00 && cc < 0xA000 ) ||
22041 (cc >= 0x3400 && cc < 0x4E00 ) ||
22042 (cc >= 0xf900 && cc < 0xfb00 )
22048 if(this.owner.fireEvent('beforesync', this, html) !== false){
22049 this.el.dom.value = html;
22050 this.owner.fireEvent('sync', this, html);
22056 * Protected method that will not generally be called directly. Pushes the value of the textarea
22057 * into the iframe editor.
22059 pushValue : function(){
22060 if(this.initialized){
22061 var v = this.el.dom.value.trim();
22063 // if(v.length < 1){
22067 if(this.owner.fireEvent('beforepush', this, v) !== false){
22068 var d = (this.doc.body || this.doc.documentElement);
22070 this.cleanUpPaste();
22071 this.el.dom.value = d.innerHTML;
22072 this.owner.fireEvent('push', this, v);
22078 deferFocus : function(){
22079 this.focus.defer(10, this);
22083 focus : function(){
22084 if(this.win && !this.sourceEditMode){
22091 assignDocWin: function()
22093 var iframe = this.iframe;
22096 this.doc = iframe.contentWindow.document;
22097 this.win = iframe.contentWindow;
22099 // if (!Roo.get(this.frameId)) {
22102 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22103 // this.win = Roo.get(this.frameId).dom.contentWindow;
22105 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22109 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22110 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22115 initEditor : function(){
22116 //console.log("INIT EDITOR");
22117 this.assignDocWin();
22121 this.doc.designMode="on";
22123 this.doc.write(this.getDocMarkup());
22126 var dbody = (this.doc.body || this.doc.documentElement);
22127 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22128 // this copies styles from the containing element into thsi one..
22129 // not sure why we need all of this..
22130 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22132 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22133 //ss['background-attachment'] = 'fixed'; // w3c
22134 dbody.bgProperties = 'fixed'; // ie
22135 //Roo.DomHelper.applyStyles(dbody, ss);
22136 Roo.EventManager.on(this.doc, {
22137 //'mousedown': this.onEditorEvent,
22138 'mouseup': this.onEditorEvent,
22139 'dblclick': this.onEditorEvent,
22140 'click': this.onEditorEvent,
22141 'keyup': this.onEditorEvent,
22146 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22148 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22149 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22151 this.initialized = true;
22153 this.owner.fireEvent('initialize', this);
22158 onDestroy : function(){
22164 //for (var i =0; i < this.toolbars.length;i++) {
22165 // // fixme - ask toolbars for heights?
22166 // this.toolbars[i].onDestroy();
22169 //this.wrap.dom.innerHTML = '';
22170 //this.wrap.remove();
22175 onFirstFocus : function(){
22177 this.assignDocWin();
22180 this.activated = true;
22183 if(Roo.isGecko){ // prevent silly gecko errors
22185 var s = this.win.getSelection();
22186 if(!s.focusNode || s.focusNode.nodeType != 3){
22187 var r = s.getRangeAt(0);
22188 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22193 this.execCmd('useCSS', true);
22194 this.execCmd('styleWithCSS', false);
22197 this.owner.fireEvent('activate', this);
22201 adjustFont: function(btn){
22202 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22203 //if(Roo.isSafari){ // safari
22206 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22207 if(Roo.isSafari){ // safari
22208 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22209 v = (v < 10) ? 10 : v;
22210 v = (v > 48) ? 48 : v;
22211 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22216 v = Math.max(1, v+adjust);
22218 this.execCmd('FontSize', v );
22221 onEditorEvent : function(e)
22223 this.owner.fireEvent('editorevent', this, e);
22224 // this.updateToolbar();
22225 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22228 insertTag : function(tg)
22230 // could be a bit smarter... -> wrap the current selected tRoo..
22231 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22233 range = this.createRange(this.getSelection());
22234 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22235 wrappingNode.appendChild(range.extractContents());
22236 range.insertNode(wrappingNode);
22243 this.execCmd("formatblock", tg);
22247 insertText : function(txt)
22251 var range = this.createRange();
22252 range.deleteContents();
22253 //alert(Sender.getAttribute('label'));
22255 range.insertNode(this.doc.createTextNode(txt));
22261 * Executes a Midas editor command on the editor document and performs necessary focus and
22262 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22263 * @param {String} cmd The Midas command
22264 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22266 relayCmd : function(cmd, value){
22268 this.execCmd(cmd, value);
22269 this.owner.fireEvent('editorevent', this);
22270 //this.updateToolbar();
22271 this.owner.deferFocus();
22275 * Executes a Midas editor command directly on the editor document.
22276 * For visual commands, you should use {@link #relayCmd} instead.
22277 * <b>This should only be called after the editor is initialized.</b>
22278 * @param {String} cmd The Midas command
22279 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22281 execCmd : function(cmd, value){
22282 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22289 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22291 * @param {String} text | dom node..
22293 insertAtCursor : function(text)
22296 if(!this.activated){
22302 var r = this.doc.selection.createRange();
22313 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22317 // from jquery ui (MIT licenced)
22319 var win = this.win;
22321 if (win.getSelection && win.getSelection().getRangeAt) {
22322 range = win.getSelection().getRangeAt(0);
22323 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22324 range.insertNode(node);
22325 } else if (win.document.selection && win.document.selection.createRange) {
22326 // no firefox support
22327 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22328 win.document.selection.createRange().pasteHTML(txt);
22330 // no firefox support
22331 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22332 this.execCmd('InsertHTML', txt);
22341 mozKeyPress : function(e){
22343 var c = e.getCharCode(), cmd;
22346 c = String.fromCharCode(c).toLowerCase();
22360 this.cleanUpPaste.defer(100, this);
22368 e.preventDefault();
22376 fixKeys : function(){ // load time branching for fastest keydown performance
22378 return function(e){
22379 var k = e.getKey(), r;
22382 r = this.doc.selection.createRange();
22385 r.pasteHTML('    ');
22392 r = this.doc.selection.createRange();
22394 var target = r.parentElement();
22395 if(!target || target.tagName.toLowerCase() != 'li'){
22397 r.pasteHTML('<br />');
22403 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22404 this.cleanUpPaste.defer(100, this);
22410 }else if(Roo.isOpera){
22411 return function(e){
22412 var k = e.getKey();
22416 this.execCmd('InsertHTML','    ');
22419 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22420 this.cleanUpPaste.defer(100, this);
22425 }else if(Roo.isSafari){
22426 return function(e){
22427 var k = e.getKey();
22431 this.execCmd('InsertText','\t');
22435 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22436 this.cleanUpPaste.defer(100, this);
22444 getAllAncestors: function()
22446 var p = this.getSelectedNode();
22449 a.push(p); // push blank onto stack..
22450 p = this.getParentElement();
22454 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22458 a.push(this.doc.body);
22462 lastSelNode : false,
22465 getSelection : function()
22467 this.assignDocWin();
22468 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22471 getSelectedNode: function()
22473 // this may only work on Gecko!!!
22475 // should we cache this!!!!
22480 var range = this.createRange(this.getSelection()).cloneRange();
22483 var parent = range.parentElement();
22485 var testRange = range.duplicate();
22486 testRange.moveToElementText(parent);
22487 if (testRange.inRange(range)) {
22490 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22493 parent = parent.parentElement;
22498 // is ancestor a text element.
22499 var ac = range.commonAncestorContainer;
22500 if (ac.nodeType == 3) {
22501 ac = ac.parentNode;
22504 var ar = ac.childNodes;
22507 var other_nodes = [];
22508 var has_other_nodes = false;
22509 for (var i=0;i<ar.length;i++) {
22510 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22513 // fullly contained node.
22515 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22520 // probably selected..
22521 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22522 other_nodes.push(ar[i]);
22526 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22531 has_other_nodes = true;
22533 if (!nodes.length && other_nodes.length) {
22534 nodes= other_nodes;
22536 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22542 createRange: function(sel)
22544 // this has strange effects when using with
22545 // top toolbar - not sure if it's a great idea.
22546 //this.editor.contentWindow.focus();
22547 if (typeof sel != "undefined") {
22549 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22551 return this.doc.createRange();
22554 return this.doc.createRange();
22557 getParentElement: function()
22560 this.assignDocWin();
22561 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22563 var range = this.createRange(sel);
22566 var p = range.commonAncestorContainer;
22567 while (p.nodeType == 3) { // text node
22578 * Range intersection.. the hard stuff...
22582 * [ -- selected range --- ]
22586 * if end is before start or hits it. fail.
22587 * if start is after end or hits it fail.
22589 * if either hits (but other is outside. - then it's not
22595 // @see http://www.thismuchiknow.co.uk/?p=64.
22596 rangeIntersectsNode : function(range, node)
22598 var nodeRange = node.ownerDocument.createRange();
22600 nodeRange.selectNode(node);
22602 nodeRange.selectNodeContents(node);
22605 var rangeStartRange = range.cloneRange();
22606 rangeStartRange.collapse(true);
22608 var rangeEndRange = range.cloneRange();
22609 rangeEndRange.collapse(false);
22611 var nodeStartRange = nodeRange.cloneRange();
22612 nodeStartRange.collapse(true);
22614 var nodeEndRange = nodeRange.cloneRange();
22615 nodeEndRange.collapse(false);
22617 return rangeStartRange.compareBoundaryPoints(
22618 Range.START_TO_START, nodeEndRange) == -1 &&
22619 rangeEndRange.compareBoundaryPoints(
22620 Range.START_TO_START, nodeStartRange) == 1;
22624 rangeCompareNode : function(range, node)
22626 var nodeRange = node.ownerDocument.createRange();
22628 nodeRange.selectNode(node);
22630 nodeRange.selectNodeContents(node);
22634 range.collapse(true);
22636 nodeRange.collapse(true);
22638 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22639 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22641 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22643 var nodeIsBefore = ss == 1;
22644 var nodeIsAfter = ee == -1;
22646 if (nodeIsBefore && nodeIsAfter) {
22649 if (!nodeIsBefore && nodeIsAfter) {
22650 return 1; //right trailed.
22653 if (nodeIsBefore && !nodeIsAfter) {
22654 return 2; // left trailed.
22660 // private? - in a new class?
22661 cleanUpPaste : function()
22663 // cleans up the whole document..
22664 Roo.log('cleanuppaste');
22666 this.cleanUpChildren(this.doc.body);
22667 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22668 if (clean != this.doc.body.innerHTML) {
22669 this.doc.body.innerHTML = clean;
22674 cleanWordChars : function(input) {// change the chars to hex code
22675 var he = Roo.HtmlEditorCore;
22677 var output = input;
22678 Roo.each(he.swapCodes, function(sw) {
22679 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22681 output = output.replace(swapper, sw[1]);
22688 cleanUpChildren : function (n)
22690 if (!n.childNodes.length) {
22693 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22694 this.cleanUpChild(n.childNodes[i]);
22701 cleanUpChild : function (node)
22704 //console.log(node);
22705 if (node.nodeName == "#text") {
22706 // clean up silly Windows -- stuff?
22709 if (node.nodeName == "#comment") {
22710 node.parentNode.removeChild(node);
22711 // clean up silly Windows -- stuff?
22714 var lcname = node.tagName.toLowerCase();
22715 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22716 // whitelist of tags..
22718 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22720 node.parentNode.removeChild(node);
22725 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22727 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22728 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22730 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22731 // remove_keep_children = true;
22734 if (remove_keep_children) {
22735 this.cleanUpChildren(node);
22736 // inserts everything just before this node...
22737 while (node.childNodes.length) {
22738 var cn = node.childNodes[0];
22739 node.removeChild(cn);
22740 node.parentNode.insertBefore(cn, node);
22742 node.parentNode.removeChild(node);
22746 if (!node.attributes || !node.attributes.length) {
22747 this.cleanUpChildren(node);
22751 function cleanAttr(n,v)
22754 if (v.match(/^\./) || v.match(/^\//)) {
22757 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22760 if (v.match(/^#/)) {
22763 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22764 node.removeAttribute(n);
22768 var cwhite = this.cwhite;
22769 var cblack = this.cblack;
22771 function cleanStyle(n,v)
22773 if (v.match(/expression/)) { //XSS?? should we even bother..
22774 node.removeAttribute(n);
22778 var parts = v.split(/;/);
22781 Roo.each(parts, function(p) {
22782 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22786 var l = p.split(':').shift().replace(/\s+/g,'');
22787 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22789 if ( cwhite.length && cblack.indexOf(l) > -1) {
22790 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22791 //node.removeAttribute(n);
22795 // only allow 'c whitelisted system attributes'
22796 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22797 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22798 //node.removeAttribute(n);
22808 if (clean.length) {
22809 node.setAttribute(n, clean.join(';'));
22811 node.removeAttribute(n);
22817 for (var i = node.attributes.length-1; i > -1 ; i--) {
22818 var a = node.attributes[i];
22821 if (a.name.toLowerCase().substr(0,2)=='on') {
22822 node.removeAttribute(a.name);
22825 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22826 node.removeAttribute(a.name);
22829 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22830 cleanAttr(a.name,a.value); // fixme..
22833 if (a.name == 'style') {
22834 cleanStyle(a.name,a.value);
22837 /// clean up MS crap..
22838 // tecnically this should be a list of valid class'es..
22841 if (a.name == 'class') {
22842 if (a.value.match(/^Mso/)) {
22843 node.className = '';
22846 if (a.value.match(/^body$/)) {
22847 node.className = '';
22858 this.cleanUpChildren(node);
22864 * Clean up MS wordisms...
22866 cleanWord : function(node)
22871 this.cleanWord(this.doc.body);
22874 if (node.nodeName == "#text") {
22875 // clean up silly Windows -- stuff?
22878 if (node.nodeName == "#comment") {
22879 node.parentNode.removeChild(node);
22880 // clean up silly Windows -- stuff?
22884 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22885 node.parentNode.removeChild(node);
22889 // remove - but keep children..
22890 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22891 while (node.childNodes.length) {
22892 var cn = node.childNodes[0];
22893 node.removeChild(cn);
22894 node.parentNode.insertBefore(cn, node);
22896 node.parentNode.removeChild(node);
22897 this.iterateChildren(node, this.cleanWord);
22901 if (node.className.length) {
22903 var cn = node.className.split(/\W+/);
22905 Roo.each(cn, function(cls) {
22906 if (cls.match(/Mso[a-zA-Z]+/)) {
22911 node.className = cna.length ? cna.join(' ') : '';
22913 node.removeAttribute("class");
22917 if (node.hasAttribute("lang")) {
22918 node.removeAttribute("lang");
22921 if (node.hasAttribute("style")) {
22923 var styles = node.getAttribute("style").split(";");
22925 Roo.each(styles, function(s) {
22926 if (!s.match(/:/)) {
22929 var kv = s.split(":");
22930 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22933 // what ever is left... we allow.
22936 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22937 if (!nstyle.length) {
22938 node.removeAttribute('style');
22941 this.iterateChildren(node, this.cleanWord);
22947 * iterateChildren of a Node, calling fn each time, using this as the scole..
22948 * @param {DomNode} node node to iterate children of.
22949 * @param {Function} fn method of this class to call on each item.
22951 iterateChildren : function(node, fn)
22953 if (!node.childNodes.length) {
22956 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22957 fn.call(this, node.childNodes[i])
22963 * cleanTableWidths.
22965 * Quite often pasting from word etc.. results in tables with column and widths.
22966 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22969 cleanTableWidths : function(node)
22974 this.cleanTableWidths(this.doc.body);
22979 if (node.nodeName == "#text" || node.nodeName == "#comment") {
22982 Roo.log(node.tagName);
22983 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22984 this.iterateChildren(node, this.cleanTableWidths);
22987 if (node.hasAttribute('width')) {
22988 node.removeAttribute('width');
22992 if (node.hasAttribute("style")) {
22995 var styles = node.getAttribute("style").split(";");
22997 Roo.each(styles, function(s) {
22998 if (!s.match(/:/)) {
23001 var kv = s.split(":");
23002 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23005 // what ever is left... we allow.
23008 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23009 if (!nstyle.length) {
23010 node.removeAttribute('style');
23014 this.iterateChildren(node, this.cleanTableWidths);
23022 domToHTML : function(currentElement, depth, nopadtext) {
23024 depth = depth || 0;
23025 nopadtext = nopadtext || false;
23027 if (!currentElement) {
23028 return this.domToHTML(this.doc.body);
23031 //Roo.log(currentElement);
23033 var allText = false;
23034 var nodeName = currentElement.nodeName;
23035 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23037 if (nodeName == '#text') {
23039 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23044 if (nodeName != 'BODY') {
23047 // Prints the node tagName, such as <A>, <IMG>, etc
23050 for(i = 0; i < currentElement.attributes.length;i++) {
23052 var aname = currentElement.attributes.item(i).name;
23053 if (!currentElement.attributes.item(i).value.length) {
23056 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23059 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23068 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23071 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23076 // Traverse the tree
23078 var currentElementChild = currentElement.childNodes.item(i);
23079 var allText = true;
23080 var innerHTML = '';
23082 while (currentElementChild) {
23083 // Formatting code (indent the tree so it looks nice on the screen)
23084 var nopad = nopadtext;
23085 if (lastnode == 'SPAN') {
23089 if (currentElementChild.nodeName == '#text') {
23090 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23091 toadd = nopadtext ? toadd : toadd.trim();
23092 if (!nopad && toadd.length > 80) {
23093 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23095 innerHTML += toadd;
23098 currentElementChild = currentElement.childNodes.item(i);
23104 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23106 // Recursively traverse the tree structure of the child node
23107 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23108 lastnode = currentElementChild.nodeName;
23110 currentElementChild=currentElement.childNodes.item(i);
23116 // The remaining code is mostly for formatting the tree
23117 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23122 ret+= "</"+tagName+">";
23128 applyBlacklists : function()
23130 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23131 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23135 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23136 if (b.indexOf(tag) > -1) {
23139 this.white.push(tag);
23143 Roo.each(w, function(tag) {
23144 if (b.indexOf(tag) > -1) {
23147 if (this.white.indexOf(tag) > -1) {
23150 this.white.push(tag);
23155 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23156 if (w.indexOf(tag) > -1) {
23159 this.black.push(tag);
23163 Roo.each(b, function(tag) {
23164 if (w.indexOf(tag) > -1) {
23167 if (this.black.indexOf(tag) > -1) {
23170 this.black.push(tag);
23175 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23176 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23180 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23181 if (b.indexOf(tag) > -1) {
23184 this.cwhite.push(tag);
23188 Roo.each(w, function(tag) {
23189 if (b.indexOf(tag) > -1) {
23192 if (this.cwhite.indexOf(tag) > -1) {
23195 this.cwhite.push(tag);
23200 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23201 if (w.indexOf(tag) > -1) {
23204 this.cblack.push(tag);
23208 Roo.each(b, function(tag) {
23209 if (w.indexOf(tag) > -1) {
23212 if (this.cblack.indexOf(tag) > -1) {
23215 this.cblack.push(tag);
23220 setStylesheets : function(stylesheets)
23222 if(typeof(stylesheets) == 'string'){
23223 Roo.get(this.iframe.contentDocument.head).createChild({
23225 rel : 'stylesheet',
23234 Roo.each(stylesheets, function(s) {
23239 Roo.get(_this.iframe.contentDocument.head).createChild({
23241 rel : 'stylesheet',
23250 removeStylesheets : function()
23254 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23259 setStyle : function(style)
23261 Roo.get(this.iframe.contentDocument.head).createChild({
23270 // hide stuff that is not compatible
23284 * @event specialkey
23288 * @cfg {String} fieldClass @hide
23291 * @cfg {String} focusClass @hide
23294 * @cfg {String} autoCreate @hide
23297 * @cfg {String} inputType @hide
23300 * @cfg {String} invalidClass @hide
23303 * @cfg {String} invalidText @hide
23306 * @cfg {String} msgFx @hide
23309 * @cfg {String} validateOnBlur @hide
23313 Roo.HtmlEditorCore.white = [
23314 'area', 'br', 'img', 'input', 'hr', 'wbr',
23316 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23317 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23318 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23319 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23320 'table', 'ul', 'xmp',
23322 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23325 'dir', 'menu', 'ol', 'ul', 'dl',
23331 Roo.HtmlEditorCore.black = [
23332 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23334 'base', 'basefont', 'bgsound', 'blink', 'body',
23335 'frame', 'frameset', 'head', 'html', 'ilayer',
23336 'iframe', 'layer', 'link', 'meta', 'object',
23337 'script', 'style' ,'title', 'xml' // clean later..
23339 Roo.HtmlEditorCore.clean = [
23340 'script', 'style', 'title', 'xml'
23342 Roo.HtmlEditorCore.remove = [
23347 Roo.HtmlEditorCore.ablack = [
23351 Roo.HtmlEditorCore.aclean = [
23352 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23356 Roo.HtmlEditorCore.pwhite= [
23357 'http', 'https', 'mailto'
23360 // white listed style attributes.
23361 Roo.HtmlEditorCore.cwhite= [
23362 // 'text-align', /// default is to allow most things..
23368 // black listed style attributes.
23369 Roo.HtmlEditorCore.cblack= [
23370 // 'font-size' -- this can be set by the project
23374 Roo.HtmlEditorCore.swapCodes =[
23393 * @class Roo.bootstrap.HtmlEditor
23394 * @extends Roo.bootstrap.TextArea
23395 * Bootstrap HtmlEditor class
23398 * Create a new HtmlEditor
23399 * @param {Object} config The config object
23402 Roo.bootstrap.HtmlEditor = function(config){
23403 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23404 if (!this.toolbars) {
23405 this.toolbars = [];
23408 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23411 * @event initialize
23412 * Fires when the editor is fully initialized (including the iframe)
23413 * @param {HtmlEditor} this
23418 * Fires when the editor is first receives the focus. Any insertion must wait
23419 * until after this event.
23420 * @param {HtmlEditor} this
23424 * @event beforesync
23425 * Fires before the textarea is updated with content from the editor iframe. Return false
23426 * to cancel the sync.
23427 * @param {HtmlEditor} this
23428 * @param {String} html
23432 * @event beforepush
23433 * Fires before the iframe editor is updated with content from the textarea. Return false
23434 * to cancel the push.
23435 * @param {HtmlEditor} this
23436 * @param {String} html
23441 * Fires when the textarea is updated with content from the editor iframe.
23442 * @param {HtmlEditor} this
23443 * @param {String} html
23448 * Fires when the iframe editor is updated with content from the textarea.
23449 * @param {HtmlEditor} this
23450 * @param {String} html
23454 * @event editmodechange
23455 * Fires when the editor switches edit modes
23456 * @param {HtmlEditor} this
23457 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23459 editmodechange: true,
23461 * @event editorevent
23462 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23463 * @param {HtmlEditor} this
23467 * @event firstfocus
23468 * Fires when on first focus - needed by toolbars..
23469 * @param {HtmlEditor} this
23474 * Auto save the htmlEditor value as a file into Events
23475 * @param {HtmlEditor} this
23479 * @event savedpreview
23480 * preview the saved version of htmlEditor
23481 * @param {HtmlEditor} this
23488 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23492 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23497 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23502 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23507 * @cfg {Number} height (in pixels)
23511 * @cfg {Number} width (in pixels)
23516 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23519 stylesheets: false,
23524 // private properties
23525 validationEvent : false,
23527 initialized : false,
23530 onFocus : Roo.emptyFn,
23532 hideMode:'offsets',
23534 tbContainer : false,
23538 toolbarContainer :function() {
23539 return this.wrap.select('.x-html-editor-tb',true).first();
23543 * Protected method that will not generally be called directly. It
23544 * is called when the editor creates its toolbar. Override this method if you need to
23545 * add custom toolbar buttons.
23546 * @param {HtmlEditor} editor
23548 createToolbar : function(){
23549 Roo.log('renewing');
23550 Roo.log("create toolbars");
23552 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23553 this.toolbars[0].render(this.toolbarContainer());
23557 // if (!editor.toolbars || !editor.toolbars.length) {
23558 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23561 // for (var i =0 ; i < editor.toolbars.length;i++) {
23562 // editor.toolbars[i] = Roo.factory(
23563 // typeof(editor.toolbars[i]) == 'string' ?
23564 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23565 // Roo.bootstrap.HtmlEditor);
23566 // editor.toolbars[i].init(editor);
23572 onRender : function(ct, position)
23574 // Roo.log("Call onRender: " + this.xtype);
23576 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23578 this.wrap = this.inputEl().wrap({
23579 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23582 this.editorcore.onRender(ct, position);
23584 if (this.resizable) {
23585 this.resizeEl = new Roo.Resizable(this.wrap, {
23589 minHeight : this.height,
23590 height: this.height,
23591 handles : this.resizable,
23594 resize : function(r, w, h) {
23595 _t.onResize(w,h); // -something
23601 this.createToolbar(this);
23604 if(!this.width && this.resizable){
23605 this.setSize(this.wrap.getSize());
23607 if (this.resizeEl) {
23608 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23609 // should trigger onReize..
23615 onResize : function(w, h)
23617 Roo.log('resize: ' +w + ',' + h );
23618 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23622 if(this.inputEl() ){
23623 if(typeof w == 'number'){
23624 var aw = w - this.wrap.getFrameWidth('lr');
23625 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23628 if(typeof h == 'number'){
23629 var tbh = -11; // fixme it needs to tool bar size!
23630 for (var i =0; i < this.toolbars.length;i++) {
23631 // fixme - ask toolbars for heights?
23632 tbh += this.toolbars[i].el.getHeight();
23633 //if (this.toolbars[i].footer) {
23634 // tbh += this.toolbars[i].footer.el.getHeight();
23642 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23643 ah -= 5; // knock a few pixes off for look..
23644 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23648 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23649 this.editorcore.onResize(ew,eh);
23654 * Toggles the editor between standard and source edit mode.
23655 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23657 toggleSourceEdit : function(sourceEditMode)
23659 this.editorcore.toggleSourceEdit(sourceEditMode);
23661 if(this.editorcore.sourceEditMode){
23662 Roo.log('editor - showing textarea');
23665 // Roo.log(this.syncValue());
23667 this.inputEl().removeClass(['hide', 'x-hidden']);
23668 this.inputEl().dom.removeAttribute('tabIndex');
23669 this.inputEl().focus();
23671 Roo.log('editor - hiding textarea');
23673 // Roo.log(this.pushValue());
23676 this.inputEl().addClass(['hide', 'x-hidden']);
23677 this.inputEl().dom.setAttribute('tabIndex', -1);
23678 //this.deferFocus();
23681 if(this.resizable){
23682 this.setSize(this.wrap.getSize());
23685 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23688 // private (for BoxComponent)
23689 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23691 // private (for BoxComponent)
23692 getResizeEl : function(){
23696 // private (for BoxComponent)
23697 getPositionEl : function(){
23702 initEvents : function(){
23703 this.originalValue = this.getValue();
23707 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23710 // markInvalid : Roo.emptyFn,
23712 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23715 // clearInvalid : Roo.emptyFn,
23717 setValue : function(v){
23718 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23719 this.editorcore.pushValue();
23724 deferFocus : function(){
23725 this.focus.defer(10, this);
23729 focus : function(){
23730 this.editorcore.focus();
23736 onDestroy : function(){
23742 for (var i =0; i < this.toolbars.length;i++) {
23743 // fixme - ask toolbars for heights?
23744 this.toolbars[i].onDestroy();
23747 this.wrap.dom.innerHTML = '';
23748 this.wrap.remove();
23753 onFirstFocus : function(){
23754 //Roo.log("onFirstFocus");
23755 this.editorcore.onFirstFocus();
23756 for (var i =0; i < this.toolbars.length;i++) {
23757 this.toolbars[i].onFirstFocus();
23763 syncValue : function()
23765 this.editorcore.syncValue();
23768 pushValue : function()
23770 this.editorcore.pushValue();
23774 // hide stuff that is not compatible
23788 * @event specialkey
23792 * @cfg {String} fieldClass @hide
23795 * @cfg {String} focusClass @hide
23798 * @cfg {String} autoCreate @hide
23801 * @cfg {String} inputType @hide
23804 * @cfg {String} invalidClass @hide
23807 * @cfg {String} invalidText @hide
23810 * @cfg {String} msgFx @hide
23813 * @cfg {String} validateOnBlur @hide
23822 Roo.namespace('Roo.bootstrap.htmleditor');
23824 * @class Roo.bootstrap.HtmlEditorToolbar1
23829 new Roo.bootstrap.HtmlEditor({
23832 new Roo.bootstrap.HtmlEditorToolbar1({
23833 disable : { fonts: 1 , format: 1, ..., ... , ...],
23839 * @cfg {Object} disable List of elements to disable..
23840 * @cfg {Array} btns List of additional buttons.
23844 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23847 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23850 Roo.apply(this, config);
23852 // default disabled, based on 'good practice'..
23853 this.disable = this.disable || {};
23854 Roo.applyIf(this.disable, {
23857 specialElements : true
23859 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23861 this.editor = config.editor;
23862 this.editorcore = config.editor.editorcore;
23864 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23866 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23867 // dont call parent... till later.
23869 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23874 editorcore : false,
23879 "h1","h2","h3","h4","h5","h6",
23881 "abbr", "acronym", "address", "cite", "samp", "var",
23885 onRender : function(ct, position)
23887 // Roo.log("Call onRender: " + this.xtype);
23889 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23891 this.el.dom.style.marginBottom = '0';
23893 var editorcore = this.editorcore;
23894 var editor= this.editor;
23897 var btn = function(id,cmd , toggle, handler, html){
23899 var event = toggle ? 'toggle' : 'click';
23904 xns: Roo.bootstrap,
23907 enableToggle:toggle !== false,
23909 pressed : toggle ? false : null,
23912 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23913 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23919 // var cb_box = function...
23924 xns: Roo.bootstrap,
23925 glyphicon : 'font',
23929 xns: Roo.bootstrap,
23933 Roo.each(this.formats, function(f) {
23934 style.menu.items.push({
23936 xns: Roo.bootstrap,
23937 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23942 editorcore.insertTag(this.tagname);
23949 children.push(style);
23951 btn('bold',false,true);
23952 btn('italic',false,true);
23953 btn('align-left', 'justifyleft',true);
23954 btn('align-center', 'justifycenter',true);
23955 btn('align-right' , 'justifyright',true);
23956 btn('link', false, false, function(btn) {
23957 //Roo.log("create link?");
23958 var url = prompt(this.createLinkText, this.defaultLinkValue);
23959 if(url && url != 'http:/'+'/'){
23960 this.editorcore.relayCmd('createlink', url);
23963 btn('list','insertunorderedlist',true);
23964 btn('pencil', false,true, function(btn){
23966 this.toggleSourceEdit(btn.pressed);
23969 if (this.editor.btns.length > 0) {
23970 for (var i = 0; i<this.editor.btns.length; i++) {
23971 children.push(this.editor.btns[i]);
23979 xns: Roo.bootstrap,
23984 xns: Roo.bootstrap,
23989 cog.menu.items.push({
23991 xns: Roo.bootstrap,
23992 html : Clean styles,
23997 editorcore.insertTag(this.tagname);
24006 this.xtype = 'NavSimplebar';
24008 for(var i=0;i< children.length;i++) {
24010 this.buttons.add(this.addxtypeChild(children[i]));
24014 editor.on('editorevent', this.updateToolbar, this);
24016 onBtnClick : function(id)
24018 this.editorcore.relayCmd(id);
24019 this.editorcore.focus();
24023 * Protected method that will not generally be called directly. It triggers
24024 * a toolbar update by reading the markup state of the current selection in the editor.
24026 updateToolbar: function(){
24028 if(!this.editorcore.activated){
24029 this.editor.onFirstFocus(); // is this neeed?
24033 var btns = this.buttons;
24034 var doc = this.editorcore.doc;
24035 btns.get('bold').setActive(doc.queryCommandState('bold'));
24036 btns.get('italic').setActive(doc.queryCommandState('italic'));
24037 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24039 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24040 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24041 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24043 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24044 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24047 var ans = this.editorcore.getAllAncestors();
24048 if (this.formatCombo) {
24051 var store = this.formatCombo.store;
24052 this.formatCombo.setValue("");
24053 for (var i =0; i < ans.length;i++) {
24054 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24056 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24064 // hides menus... - so this cant be on a menu...
24065 Roo.bootstrap.MenuMgr.hideAll();
24067 Roo.bootstrap.MenuMgr.hideAll();
24068 //this.editorsyncValue();
24070 onFirstFocus: function() {
24071 this.buttons.each(function(item){
24075 toggleSourceEdit : function(sourceEditMode){
24078 if(sourceEditMode){
24079 Roo.log("disabling buttons");
24080 this.buttons.each( function(item){
24081 if(item.cmd != 'pencil'){
24087 Roo.log("enabling buttons");
24088 if(this.editorcore.initialized){
24089 this.buttons.each( function(item){
24095 Roo.log("calling toggole on editor");
24096 // tell the editor that it's been pressed..
24097 this.editor.toggleSourceEdit(sourceEditMode);
24107 * @class Roo.bootstrap.Table.AbstractSelectionModel
24108 * @extends Roo.util.Observable
24109 * Abstract base class for grid SelectionModels. It provides the interface that should be
24110 * implemented by descendant classes. This class should not be directly instantiated.
24113 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24114 this.locked = false;
24115 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24119 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24120 /** @ignore Called by the grid automatically. Do not call directly. */
24121 init : function(grid){
24127 * Locks the selections.
24130 this.locked = true;
24134 * Unlocks the selections.
24136 unlock : function(){
24137 this.locked = false;
24141 * Returns true if the selections are locked.
24142 * @return {Boolean}
24144 isLocked : function(){
24145 return this.locked;
24149 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24150 * @class Roo.bootstrap.Table.RowSelectionModel
24151 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24152 * It supports multiple selections and keyboard selection/navigation.
24154 * @param {Object} config
24157 Roo.bootstrap.Table.RowSelectionModel = function(config){
24158 Roo.apply(this, config);
24159 this.selections = new Roo.util.MixedCollection(false, function(o){
24164 this.lastActive = false;
24168 * @event selectionchange
24169 * Fires when the selection changes
24170 * @param {SelectionModel} this
24172 "selectionchange" : true,
24174 * @event afterselectionchange
24175 * Fires after the selection changes (eg. by key press or clicking)
24176 * @param {SelectionModel} this
24178 "afterselectionchange" : true,
24180 * @event beforerowselect
24181 * Fires when a row is selected being selected, return false to cancel.
24182 * @param {SelectionModel} this
24183 * @param {Number} rowIndex The selected index
24184 * @param {Boolean} keepExisting False if other selections will be cleared
24186 "beforerowselect" : true,
24189 * Fires when a row is selected.
24190 * @param {SelectionModel} this
24191 * @param {Number} rowIndex The selected index
24192 * @param {Roo.data.Record} r The record
24194 "rowselect" : true,
24196 * @event rowdeselect
24197 * Fires when a row is deselected.
24198 * @param {SelectionModel} this
24199 * @param {Number} rowIndex The selected index
24201 "rowdeselect" : true
24203 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24204 this.locked = false;
24207 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24209 * @cfg {Boolean} singleSelect
24210 * True to allow selection of only one row at a time (defaults to false)
24212 singleSelect : false,
24215 initEvents : function()
24218 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24219 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24220 //}else{ // allow click to work like normal
24221 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24223 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24224 this.grid.on("rowclick", this.handleMouseDown, this);
24226 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24227 "up" : function(e){
24229 this.selectPrevious(e.shiftKey);
24230 }else if(this.last !== false && this.lastActive !== false){
24231 var last = this.last;
24232 this.selectRange(this.last, this.lastActive-1);
24233 this.grid.getView().focusRow(this.lastActive);
24234 if(last !== false){
24238 this.selectFirstRow();
24240 this.fireEvent("afterselectionchange", this);
24242 "down" : function(e){
24244 this.selectNext(e.shiftKey);
24245 }else if(this.last !== false && this.lastActive !== false){
24246 var last = this.last;
24247 this.selectRange(this.last, this.lastActive+1);
24248 this.grid.getView().focusRow(this.lastActive);
24249 if(last !== false){
24253 this.selectFirstRow();
24255 this.fireEvent("afterselectionchange", this);
24259 this.grid.store.on('load', function(){
24260 this.selections.clear();
24263 var view = this.grid.view;
24264 view.on("refresh", this.onRefresh, this);
24265 view.on("rowupdated", this.onRowUpdated, this);
24266 view.on("rowremoved", this.onRemove, this);
24271 onRefresh : function()
24273 var ds = this.grid.store, i, v = this.grid.view;
24274 var s = this.selections;
24275 s.each(function(r){
24276 if((i = ds.indexOfId(r.id)) != -1){
24285 onRemove : function(v, index, r){
24286 this.selections.remove(r);
24290 onRowUpdated : function(v, index, r){
24291 if(this.isSelected(r)){
24292 v.onRowSelect(index);
24298 * @param {Array} records The records to select
24299 * @param {Boolean} keepExisting (optional) True to keep existing selections
24301 selectRecords : function(records, keepExisting)
24304 this.clearSelections();
24306 var ds = this.grid.store;
24307 for(var i = 0, len = records.length; i < len; i++){
24308 this.selectRow(ds.indexOf(records[i]), true);
24313 * Gets the number of selected rows.
24316 getCount : function(){
24317 return this.selections.length;
24321 * Selects the first row in the grid.
24323 selectFirstRow : function(){
24328 * Select the last row.
24329 * @param {Boolean} keepExisting (optional) True to keep existing selections
24331 selectLastRow : function(keepExisting){
24332 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24333 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24337 * Selects the row immediately following the last selected row.
24338 * @param {Boolean} keepExisting (optional) True to keep existing selections
24340 selectNext : function(keepExisting)
24342 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24343 this.selectRow(this.last+1, keepExisting);
24344 this.grid.getView().focusRow(this.last);
24349 * Selects the row that precedes the last selected row.
24350 * @param {Boolean} keepExisting (optional) True to keep existing selections
24352 selectPrevious : function(keepExisting){
24354 this.selectRow(this.last-1, keepExisting);
24355 this.grid.getView().focusRow(this.last);
24360 * Returns the selected records
24361 * @return {Array} Array of selected records
24363 getSelections : function(){
24364 return [].concat(this.selections.items);
24368 * Returns the first selected record.
24371 getSelected : function(){
24372 return this.selections.itemAt(0);
24377 * Clears all selections.
24379 clearSelections : function(fast)
24385 var ds = this.grid.store;
24386 var s = this.selections;
24387 s.each(function(r){
24388 this.deselectRow(ds.indexOfId(r.id));
24392 this.selections.clear();
24399 * Selects all rows.
24401 selectAll : function(){
24405 this.selections.clear();
24406 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24407 this.selectRow(i, true);
24412 * Returns True if there is a selection.
24413 * @return {Boolean}
24415 hasSelection : function(){
24416 return this.selections.length > 0;
24420 * Returns True if the specified row is selected.
24421 * @param {Number/Record} record The record or index of the record to check
24422 * @return {Boolean}
24424 isSelected : function(index){
24425 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24426 return (r && this.selections.key(r.id) ? true : false);
24430 * Returns True if the specified record id is selected.
24431 * @param {String} id The id of record to check
24432 * @return {Boolean}
24434 isIdSelected : function(id){
24435 return (this.selections.key(id) ? true : false);
24440 handleMouseDBClick : function(e, t){
24444 handleMouseDown : function(e, t)
24446 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24447 if(this.isLocked() || rowIndex < 0 ){
24450 if(e.shiftKey && this.last !== false){
24451 var last = this.last;
24452 this.selectRange(last, rowIndex, e.ctrlKey);
24453 this.last = last; // reset the last
24457 var isSelected = this.isSelected(rowIndex);
24458 //Roo.log("select row:" + rowIndex);
24460 this.deselectRow(rowIndex);
24462 this.selectRow(rowIndex, true);
24466 if(e.button !== 0 && isSelected){
24467 alert('rowIndex 2: ' + rowIndex);
24468 view.focusRow(rowIndex);
24469 }else if(e.ctrlKey && isSelected){
24470 this.deselectRow(rowIndex);
24471 }else if(!isSelected){
24472 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24473 view.focusRow(rowIndex);
24477 this.fireEvent("afterselectionchange", this);
24480 handleDragableRowClick : function(grid, rowIndex, e)
24482 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24483 this.selectRow(rowIndex, false);
24484 grid.view.focusRow(rowIndex);
24485 this.fireEvent("afterselectionchange", this);
24490 * Selects multiple rows.
24491 * @param {Array} rows Array of the indexes of the row to select
24492 * @param {Boolean} keepExisting (optional) True to keep existing selections
24494 selectRows : function(rows, keepExisting){
24496 this.clearSelections();
24498 for(var i = 0, len = rows.length; i < len; i++){
24499 this.selectRow(rows[i], true);
24504 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24505 * @param {Number} startRow The index of the first row in the range
24506 * @param {Number} endRow The index of the last row in the range
24507 * @param {Boolean} keepExisting (optional) True to retain existing selections
24509 selectRange : function(startRow, endRow, keepExisting){
24514 this.clearSelections();
24516 if(startRow <= endRow){
24517 for(var i = startRow; i <= endRow; i++){
24518 this.selectRow(i, true);
24521 for(var i = startRow; i >= endRow; i--){
24522 this.selectRow(i, true);
24528 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24529 * @param {Number} startRow The index of the first row in the range
24530 * @param {Number} endRow The index of the last row in the range
24532 deselectRange : function(startRow, endRow, preventViewNotify){
24536 for(var i = startRow; i <= endRow; i++){
24537 this.deselectRow(i, preventViewNotify);
24543 * @param {Number} row The index of the row to select
24544 * @param {Boolean} keepExisting (optional) True to keep existing selections
24546 selectRow : function(index, keepExisting, preventViewNotify)
24548 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24551 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24552 if(!keepExisting || this.singleSelect){
24553 this.clearSelections();
24556 var r = this.grid.store.getAt(index);
24557 //console.log('selectRow - record id :' + r.id);
24559 this.selections.add(r);
24560 this.last = this.lastActive = index;
24561 if(!preventViewNotify){
24562 var proxy = new Roo.Element(
24563 this.grid.getRowDom(index)
24565 proxy.addClass('bg-info info');
24567 this.fireEvent("rowselect", this, index, r);
24568 this.fireEvent("selectionchange", this);
24574 * @param {Number} row The index of the row to deselect
24576 deselectRow : function(index, preventViewNotify)
24581 if(this.last == index){
24584 if(this.lastActive == index){
24585 this.lastActive = false;
24588 var r = this.grid.store.getAt(index);
24593 this.selections.remove(r);
24594 //.console.log('deselectRow - record id :' + r.id);
24595 if(!preventViewNotify){
24597 var proxy = new Roo.Element(
24598 this.grid.getRowDom(index)
24600 proxy.removeClass('bg-info info');
24602 this.fireEvent("rowdeselect", this, index);
24603 this.fireEvent("selectionchange", this);
24607 restoreLast : function(){
24609 this.last = this._last;
24614 acceptsNav : function(row, col, cm){
24615 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24619 onEditorKey : function(field, e){
24620 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24625 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24627 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24629 }else if(k == e.ENTER && !e.ctrlKey){
24633 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24635 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24637 }else if(k == e.ESC){
24641 g.startEditing(newCell[0], newCell[1]);
24647 * Ext JS Library 1.1.1
24648 * Copyright(c) 2006-2007, Ext JS, LLC.
24650 * Originally Released Under LGPL - original licence link has changed is not relivant.
24653 * <script type="text/javascript">
24657 * @class Roo.bootstrap.PagingToolbar
24658 * @extends Roo.bootstrap.NavSimplebar
24659 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24661 * Create a new PagingToolbar
24662 * @param {Object} config The config object
24663 * @param {Roo.data.Store} store
24665 Roo.bootstrap.PagingToolbar = function(config)
24667 // old args format still supported... - xtype is prefered..
24668 // created from xtype...
24670 this.ds = config.dataSource;
24672 if (config.store && !this.ds) {
24673 this.store= Roo.factory(config.store, Roo.data);
24674 this.ds = this.store;
24675 this.ds.xmodule = this.xmodule || false;
24678 this.toolbarItems = [];
24679 if (config.items) {
24680 this.toolbarItems = config.items;
24683 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24688 this.bind(this.ds);
24691 if (Roo.bootstrap.version == 4) {
24692 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24694 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24699 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24701 * @cfg {Roo.data.Store} dataSource
24702 * The underlying data store providing the paged data
24705 * @cfg {String/HTMLElement/Element} container
24706 * container The id or element that will contain the toolbar
24709 * @cfg {Boolean} displayInfo
24710 * True to display the displayMsg (defaults to false)
24713 * @cfg {Number} pageSize
24714 * The number of records to display per page (defaults to 20)
24718 * @cfg {String} displayMsg
24719 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24721 displayMsg : 'Displaying {0} - {1} of {2}',
24723 * @cfg {String} emptyMsg
24724 * The message to display when no records are found (defaults to "No data to display")
24726 emptyMsg : 'No data to display',
24728 * Customizable piece of the default paging text (defaults to "Page")
24731 beforePageText : "Page",
24733 * Customizable piece of the default paging text (defaults to "of %0")
24736 afterPageText : "of {0}",
24738 * Customizable piece of the default paging text (defaults to "First Page")
24741 firstText : "First Page",
24743 * Customizable piece of the default paging text (defaults to "Previous Page")
24746 prevText : "Previous Page",
24748 * Customizable piece of the default paging text (defaults to "Next Page")
24751 nextText : "Next Page",
24753 * Customizable piece of the default paging text (defaults to "Last Page")
24756 lastText : "Last Page",
24758 * Customizable piece of the default paging text (defaults to "Refresh")
24761 refreshText : "Refresh",
24765 onRender : function(ct, position)
24767 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24768 this.navgroup.parentId = this.id;
24769 this.navgroup.onRender(this.el, null);
24770 // add the buttons to the navgroup
24772 if(this.displayInfo){
24773 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24774 this.displayEl = this.el.select('.x-paging-info', true).first();
24775 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24776 // this.displayEl = navel.el.select('span',true).first();
24782 Roo.each(_this.buttons, function(e){ // this might need to use render????
24783 Roo.factory(e).render(_this.el);
24787 Roo.each(_this.toolbarItems, function(e) {
24788 _this.navgroup.addItem(e);
24792 this.first = this.navgroup.addItem({
24793 tooltip: this.firstText,
24794 cls: "prev btn-outline-secondary",
24795 html : ' <i class="fa fa-step-backward"></i>',
24797 preventDefault: true,
24798 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24801 this.prev = this.navgroup.addItem({
24802 tooltip: this.prevText,
24803 cls: "prev btn-outline-secondary",
24804 html : ' <i class="fa fa-backward"></i>',
24806 preventDefault: true,
24807 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24809 //this.addSeparator();
24812 var field = this.navgroup.addItem( {
24814 cls : 'x-paging-position btn-outline-secondary',
24816 html : this.beforePageText +
24817 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24818 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24821 this.field = field.el.select('input', true).first();
24822 this.field.on("keydown", this.onPagingKeydown, this);
24823 this.field.on("focus", function(){this.dom.select();});
24826 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24827 //this.field.setHeight(18);
24828 //this.addSeparator();
24829 this.next = this.navgroup.addItem({
24830 tooltip: this.nextText,
24831 cls: "next btn-outline-secondary",
24832 html : ' <i class="fa fa-forward"></i>',
24834 preventDefault: true,
24835 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24837 this.last = this.navgroup.addItem({
24838 tooltip: this.lastText,
24839 html : ' <i class="fa fa-step-forward"></i>',
24840 cls: "next btn-outline-secondary",
24842 preventDefault: true,
24843 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24845 //this.addSeparator();
24846 this.loading = this.navgroup.addItem({
24847 tooltip: this.refreshText,
24848 cls: "btn-outline-secondary",
24849 html : ' <i class="fa fa-refresh"></i>',
24850 preventDefault: true,
24851 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24857 updateInfo : function(){
24858 if(this.displayEl){
24859 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24860 var msg = count == 0 ?
24864 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24866 this.displayEl.update(msg);
24871 onLoad : function(ds, r, o)
24873 this.cursor = o.params.start ? o.params.start : 0;
24875 var d = this.getPageData(),
24880 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24881 this.field.dom.value = ap;
24882 this.first.setDisabled(ap == 1);
24883 this.prev.setDisabled(ap == 1);
24884 this.next.setDisabled(ap == ps);
24885 this.last.setDisabled(ap == ps);
24886 this.loading.enable();
24891 getPageData : function(){
24892 var total = this.ds.getTotalCount();
24895 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24896 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24901 onLoadError : function(){
24902 this.loading.enable();
24906 onPagingKeydown : function(e){
24907 var k = e.getKey();
24908 var d = this.getPageData();
24910 var v = this.field.dom.value, pageNum;
24911 if(!v || isNaN(pageNum = parseInt(v, 10))){
24912 this.field.dom.value = d.activePage;
24915 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24916 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24919 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))
24921 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24922 this.field.dom.value = pageNum;
24923 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24926 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24928 var v = this.field.dom.value, pageNum;
24929 var increment = (e.shiftKey) ? 10 : 1;
24930 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24933 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24934 this.field.dom.value = d.activePage;
24937 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24939 this.field.dom.value = parseInt(v, 10) + increment;
24940 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24941 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24948 beforeLoad : function(){
24950 this.loading.disable();
24955 onClick : function(which){
24964 ds.load({params:{start: 0, limit: this.pageSize}});
24967 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24970 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24973 var total = ds.getTotalCount();
24974 var extra = total % this.pageSize;
24975 var lastStart = extra ? (total - extra) : total-this.pageSize;
24976 ds.load({params:{start: lastStart, limit: this.pageSize}});
24979 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24985 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24986 * @param {Roo.data.Store} store The data store to unbind
24988 unbind : function(ds){
24989 ds.un("beforeload", this.beforeLoad, this);
24990 ds.un("load", this.onLoad, this);
24991 ds.un("loadexception", this.onLoadError, this);
24992 ds.un("remove", this.updateInfo, this);
24993 ds.un("add", this.updateInfo, this);
24994 this.ds = undefined;
24998 * Binds the paging toolbar to the specified {@link Roo.data.Store}
24999 * @param {Roo.data.Store} store The data store to bind
25001 bind : function(ds){
25002 ds.on("beforeload", this.beforeLoad, this);
25003 ds.on("load", this.onLoad, this);
25004 ds.on("loadexception", this.onLoadError, this);
25005 ds.on("remove", this.updateInfo, this);
25006 ds.on("add", this.updateInfo, this);
25017 * @class Roo.bootstrap.MessageBar
25018 * @extends Roo.bootstrap.Component
25019 * Bootstrap MessageBar class
25020 * @cfg {String} html contents of the MessageBar
25021 * @cfg {String} weight (info | success | warning | danger) default info
25022 * @cfg {String} beforeClass insert the bar before the given class
25023 * @cfg {Boolean} closable (true | false) default false
25024 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25027 * Create a new Element
25028 * @param {Object} config The config object
25031 Roo.bootstrap.MessageBar = function(config){
25032 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25035 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25041 beforeClass: 'bootstrap-sticky-wrap',
25043 getAutoCreate : function(){
25047 cls: 'alert alert-dismissable alert-' + this.weight,
25052 html: this.html || ''
25058 cfg.cls += ' alert-messages-fixed';
25072 onRender : function(ct, position)
25074 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25077 var cfg = Roo.apply({}, this.getAutoCreate());
25081 cfg.cls += ' ' + this.cls;
25084 cfg.style = this.style;
25086 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25088 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25091 this.el.select('>button.close').on('click', this.hide, this);
25097 if (!this.rendered) {
25103 this.fireEvent('show', this);
25109 if (!this.rendered) {
25115 this.fireEvent('hide', this);
25118 update : function()
25120 // var e = this.el.dom.firstChild;
25122 // if(this.closable){
25123 // e = e.nextSibling;
25126 // e.data = this.html || '';
25128 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25144 * @class Roo.bootstrap.Graph
25145 * @extends Roo.bootstrap.Component
25146 * Bootstrap Graph class
25150 @cfg {String} graphtype bar | vbar | pie
25151 @cfg {number} g_x coodinator | centre x (pie)
25152 @cfg {number} g_y coodinator | centre y (pie)
25153 @cfg {number} g_r radius (pie)
25154 @cfg {number} g_height height of the chart (respected by all elements in the set)
25155 @cfg {number} g_width width of the chart (respected by all elements in the set)
25156 @cfg {Object} title The title of the chart
25159 -opts (object) options for the chart
25161 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25162 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25164 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.
25165 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25167 o stretch (boolean)
25169 -opts (object) options for the pie
25172 o startAngle (number)
25173 o endAngle (number)
25177 * Create a new Input
25178 * @param {Object} config The config object
25181 Roo.bootstrap.Graph = function(config){
25182 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25188 * The img click event for the img.
25189 * @param {Roo.EventObject} e
25195 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25206 //g_colors: this.colors,
25213 getAutoCreate : function(){
25224 onRender : function(ct,position){
25227 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25229 if (typeof(Raphael) == 'undefined') {
25230 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25234 this.raphael = Raphael(this.el.dom);
25236 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25237 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25238 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25239 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25241 r.text(160, 10, "Single Series Chart").attr(txtattr);
25242 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25243 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25244 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25246 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25247 r.barchart(330, 10, 300, 220, data1);
25248 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25249 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25252 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25253 // r.barchart(30, 30, 560, 250, xdata, {
25254 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25255 // axis : "0 0 1 1",
25256 // axisxlabels : xdata
25257 // //yvalues : cols,
25260 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25262 // this.load(null,xdata,{
25263 // axis : "0 0 1 1",
25264 // axisxlabels : xdata
25269 load : function(graphtype,xdata,opts)
25271 this.raphael.clear();
25273 graphtype = this.graphtype;
25278 var r = this.raphael,
25279 fin = function () {
25280 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25282 fout = function () {
25283 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25285 pfin = function() {
25286 this.sector.stop();
25287 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25290 this.label[0].stop();
25291 this.label[0].attr({ r: 7.5 });
25292 this.label[1].attr({ "font-weight": 800 });
25295 pfout = function() {
25296 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25299 this.label[0].animate({ r: 5 }, 500, "bounce");
25300 this.label[1].attr({ "font-weight": 400 });
25306 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25309 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25312 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25313 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25315 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25322 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25327 setTitle: function(o)
25332 initEvents: function() {
25335 this.el.on('click', this.onClick, this);
25339 onClick : function(e)
25341 Roo.log('img onclick');
25342 this.fireEvent('click', this, e);
25354 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25357 * @class Roo.bootstrap.dash.NumberBox
25358 * @extends Roo.bootstrap.Component
25359 * Bootstrap NumberBox class
25360 * @cfg {String} headline Box headline
25361 * @cfg {String} content Box content
25362 * @cfg {String} icon Box icon
25363 * @cfg {String} footer Footer text
25364 * @cfg {String} fhref Footer href
25367 * Create a new NumberBox
25368 * @param {Object} config The config object
25372 Roo.bootstrap.dash.NumberBox = function(config){
25373 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25377 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25386 getAutoCreate : function(){
25390 cls : 'small-box ',
25398 cls : 'roo-headline',
25399 html : this.headline
25403 cls : 'roo-content',
25404 html : this.content
25418 cls : 'ion ' + this.icon
25427 cls : 'small-box-footer',
25428 href : this.fhref || '#',
25432 cfg.cn.push(footer);
25439 onRender : function(ct,position){
25440 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25447 setHeadline: function (value)
25449 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25452 setFooter: function (value, href)
25454 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25457 this.el.select('a.small-box-footer',true).first().attr('href', href);
25462 setContent: function (value)
25464 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25467 initEvents: function()
25481 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25484 * @class Roo.bootstrap.dash.TabBox
25485 * @extends Roo.bootstrap.Component
25486 * Bootstrap TabBox class
25487 * @cfg {String} title Title of the TabBox
25488 * @cfg {String} icon Icon of the TabBox
25489 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25490 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25493 * Create a new TabBox
25494 * @param {Object} config The config object
25498 Roo.bootstrap.dash.TabBox = function(config){
25499 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25504 * When a pane is added
25505 * @param {Roo.bootstrap.dash.TabPane} pane
25509 * @event activatepane
25510 * When a pane is activated
25511 * @param {Roo.bootstrap.dash.TabPane} pane
25513 "activatepane" : true
25521 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25526 tabScrollable : false,
25528 getChildContainer : function()
25530 return this.el.select('.tab-content', true).first();
25533 getAutoCreate : function(){
25537 cls: 'pull-left header',
25545 cls: 'fa ' + this.icon
25551 cls: 'nav nav-tabs pull-right',
25557 if(this.tabScrollable){
25564 cls: 'nav nav-tabs pull-right',
25575 cls: 'nav-tabs-custom',
25580 cls: 'tab-content no-padding',
25588 initEvents : function()
25590 //Roo.log('add add pane handler');
25591 this.on('addpane', this.onAddPane, this);
25594 * Updates the box title
25595 * @param {String} html to set the title to.
25597 setTitle : function(value)
25599 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25601 onAddPane : function(pane)
25603 this.panes.push(pane);
25604 //Roo.log('addpane');
25606 // tabs are rendere left to right..
25607 if(!this.showtabs){
25611 var ctr = this.el.select('.nav-tabs', true).first();
25614 var existing = ctr.select('.nav-tab',true);
25615 var qty = existing.getCount();;
25618 var tab = ctr.createChild({
25620 cls : 'nav-tab' + (qty ? '' : ' active'),
25628 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25631 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25633 pane.el.addClass('active');
25638 onTabClick : function(ev,un,ob,pane)
25640 //Roo.log('tab - prev default');
25641 ev.preventDefault();
25644 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25645 pane.tab.addClass('active');
25646 //Roo.log(pane.title);
25647 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25648 // technically we should have a deactivate event.. but maybe add later.
25649 // and it should not de-activate the selected tab...
25650 this.fireEvent('activatepane', pane);
25651 pane.el.addClass('active');
25652 pane.fireEvent('activate');
25657 getActivePane : function()
25660 Roo.each(this.panes, function(p) {
25661 if(p.el.hasClass('active')){
25682 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25684 * @class Roo.bootstrap.TabPane
25685 * @extends Roo.bootstrap.Component
25686 * Bootstrap TabPane class
25687 * @cfg {Boolean} active (false | true) Default false
25688 * @cfg {String} title title of panel
25692 * Create a new TabPane
25693 * @param {Object} config The config object
25696 Roo.bootstrap.dash.TabPane = function(config){
25697 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25703 * When a pane is activated
25704 * @param {Roo.bootstrap.dash.TabPane} pane
25711 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25716 // the tabBox that this is attached to.
25719 getAutoCreate : function()
25727 cfg.cls += ' active';
25732 initEvents : function()
25734 //Roo.log('trigger add pane handler');
25735 this.parent().fireEvent('addpane', this)
25739 * Updates the tab title
25740 * @param {String} html to set the title to.
25742 setTitle: function(str)
25748 this.tab.select('a', true).first().dom.innerHTML = str;
25765 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25768 * @class Roo.bootstrap.menu.Menu
25769 * @extends Roo.bootstrap.Component
25770 * Bootstrap Menu class - container for Menu
25771 * @cfg {String} html Text of the menu
25772 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25773 * @cfg {String} icon Font awesome icon
25774 * @cfg {String} pos Menu align to (top | bottom) default bottom
25778 * Create a new Menu
25779 * @param {Object} config The config object
25783 Roo.bootstrap.menu.Menu = function(config){
25784 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25788 * @event beforeshow
25789 * Fires before this menu is displayed
25790 * @param {Roo.bootstrap.menu.Menu} this
25794 * @event beforehide
25795 * Fires before this menu is hidden
25796 * @param {Roo.bootstrap.menu.Menu} this
25801 * Fires after this menu is displayed
25802 * @param {Roo.bootstrap.menu.Menu} this
25807 * Fires after this menu is hidden
25808 * @param {Roo.bootstrap.menu.Menu} this
25813 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25814 * @param {Roo.bootstrap.menu.Menu} this
25815 * @param {Roo.EventObject} e
25822 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25826 weight : 'default',
25831 getChildContainer : function() {
25832 if(this.isSubMenu){
25836 return this.el.select('ul.dropdown-menu', true).first();
25839 getAutoCreate : function()
25844 cls : 'roo-menu-text',
25852 cls : 'fa ' + this.icon
25863 cls : 'dropdown-button btn btn-' + this.weight,
25868 cls : 'dropdown-toggle btn btn-' + this.weight,
25878 cls : 'dropdown-menu'
25884 if(this.pos == 'top'){
25885 cfg.cls += ' dropup';
25888 if(this.isSubMenu){
25891 cls : 'dropdown-menu'
25898 onRender : function(ct, position)
25900 this.isSubMenu = ct.hasClass('dropdown-submenu');
25902 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25905 initEvents : function()
25907 if(this.isSubMenu){
25911 this.hidden = true;
25913 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25914 this.triggerEl.on('click', this.onTriggerPress, this);
25916 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25917 this.buttonEl.on('click', this.onClick, this);
25923 if(this.isSubMenu){
25927 return this.el.select('ul.dropdown-menu', true).first();
25930 onClick : function(e)
25932 this.fireEvent("click", this, e);
25935 onTriggerPress : function(e)
25937 if (this.isVisible()) {
25944 isVisible : function(){
25945 return !this.hidden;
25950 this.fireEvent("beforeshow", this);
25952 this.hidden = false;
25953 this.el.addClass('open');
25955 Roo.get(document).on("mouseup", this.onMouseUp, this);
25957 this.fireEvent("show", this);
25964 this.fireEvent("beforehide", this);
25966 this.hidden = true;
25967 this.el.removeClass('open');
25969 Roo.get(document).un("mouseup", this.onMouseUp);
25971 this.fireEvent("hide", this);
25974 onMouseUp : function()
25988 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25991 * @class Roo.bootstrap.menu.Item
25992 * @extends Roo.bootstrap.Component
25993 * Bootstrap MenuItem class
25994 * @cfg {Boolean} submenu (true | false) default false
25995 * @cfg {String} html text of the item
25996 * @cfg {String} href the link
25997 * @cfg {Boolean} disable (true | false) default false
25998 * @cfg {Boolean} preventDefault (true | false) default true
25999 * @cfg {String} icon Font awesome icon
26000 * @cfg {String} pos Submenu align to (left | right) default right
26004 * Create a new Item
26005 * @param {Object} config The config object
26009 Roo.bootstrap.menu.Item = function(config){
26010 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26014 * Fires when the mouse is hovering over this menu
26015 * @param {Roo.bootstrap.menu.Item} this
26016 * @param {Roo.EventObject} e
26021 * Fires when the mouse exits this menu
26022 * @param {Roo.bootstrap.menu.Item} this
26023 * @param {Roo.EventObject} e
26029 * The raw click event for the entire grid.
26030 * @param {Roo.EventObject} e
26036 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26041 preventDefault: true,
26046 getAutoCreate : function()
26051 cls : 'roo-menu-item-text',
26059 cls : 'fa ' + this.icon
26068 href : this.href || '#',
26075 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26079 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26081 if(this.pos == 'left'){
26082 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26089 initEvents : function()
26091 this.el.on('mouseover', this.onMouseOver, this);
26092 this.el.on('mouseout', this.onMouseOut, this);
26094 this.el.select('a', true).first().on('click', this.onClick, this);
26098 onClick : function(e)
26100 if(this.preventDefault){
26101 e.preventDefault();
26104 this.fireEvent("click", this, e);
26107 onMouseOver : function(e)
26109 if(this.submenu && this.pos == 'left'){
26110 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26113 this.fireEvent("mouseover", this, e);
26116 onMouseOut : function(e)
26118 this.fireEvent("mouseout", this, e);
26130 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26133 * @class Roo.bootstrap.menu.Separator
26134 * @extends Roo.bootstrap.Component
26135 * Bootstrap Separator class
26138 * Create a new Separator
26139 * @param {Object} config The config object
26143 Roo.bootstrap.menu.Separator = function(config){
26144 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26147 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26149 getAutoCreate : function(){
26170 * @class Roo.bootstrap.Tooltip
26171 * Bootstrap Tooltip class
26172 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26173 * to determine which dom element triggers the tooltip.
26175 * It needs to add support for additional attributes like tooltip-position
26178 * Create a new Toolti
26179 * @param {Object} config The config object
26182 Roo.bootstrap.Tooltip = function(config){
26183 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26185 this.alignment = Roo.bootstrap.Tooltip.alignment;
26187 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26188 this.alignment = config.alignment;
26193 Roo.apply(Roo.bootstrap.Tooltip, {
26195 * @function init initialize tooltip monitoring.
26199 currentTip : false,
26200 currentRegion : false,
26206 Roo.get(document).on('mouseover', this.enter ,this);
26207 Roo.get(document).on('mouseout', this.leave, this);
26210 this.currentTip = new Roo.bootstrap.Tooltip();
26213 enter : function(ev)
26215 var dom = ev.getTarget();
26217 //Roo.log(['enter',dom]);
26218 var el = Roo.fly(dom);
26219 if (this.currentEl) {
26221 //Roo.log(this.currentEl);
26222 //Roo.log(this.currentEl.contains(dom));
26223 if (this.currentEl == el) {
26226 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26232 if (this.currentTip.el) {
26233 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26237 if(!el || el.dom == document){
26243 // you can not look for children, as if el is the body.. then everythign is the child..
26244 if (!el.attr('tooltip')) { //
26245 if (!el.select("[tooltip]").elements.length) {
26248 // is the mouse over this child...?
26249 bindEl = el.select("[tooltip]").first();
26250 var xy = ev.getXY();
26251 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26252 //Roo.log("not in region.");
26255 //Roo.log("child element over..");
26258 this.currentEl = bindEl;
26259 this.currentTip.bind(bindEl);
26260 this.currentRegion = Roo.lib.Region.getRegion(dom);
26261 this.currentTip.enter();
26264 leave : function(ev)
26266 var dom = ev.getTarget();
26267 //Roo.log(['leave',dom]);
26268 if (!this.currentEl) {
26273 if (dom != this.currentEl.dom) {
26276 var xy = ev.getXY();
26277 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26280 // only activate leave if mouse cursor is outside... bounding box..
26285 if (this.currentTip) {
26286 this.currentTip.leave();
26288 //Roo.log('clear currentEl');
26289 this.currentEl = false;
26294 'left' : ['r-l', [-2,0], 'right'],
26295 'right' : ['l-r', [2,0], 'left'],
26296 'bottom' : ['t-b', [0,2], 'top'],
26297 'top' : [ 'b-t', [0,-2], 'bottom']
26303 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26308 delay : null, // can be { show : 300 , hide: 500}
26312 hoverState : null, //???
26314 placement : 'bottom',
26318 getAutoCreate : function(){
26325 cls : 'tooltip-arrow'
26328 cls : 'tooltip-inner'
26335 bind : function(el)
26341 enter : function () {
26343 if (this.timeout != null) {
26344 clearTimeout(this.timeout);
26347 this.hoverState = 'in';
26348 //Roo.log("enter - show");
26349 if (!this.delay || !this.delay.show) {
26354 this.timeout = setTimeout(function () {
26355 if (_t.hoverState == 'in') {
26358 }, this.delay.show);
26362 clearTimeout(this.timeout);
26364 this.hoverState = 'out';
26365 if (!this.delay || !this.delay.hide) {
26371 this.timeout = setTimeout(function () {
26372 //Roo.log("leave - timeout");
26374 if (_t.hoverState == 'out') {
26376 Roo.bootstrap.Tooltip.currentEl = false;
26381 show : function (msg)
26384 this.render(document.body);
26387 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26389 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26391 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26393 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26395 var placement = typeof this.placement == 'function' ?
26396 this.placement.call(this, this.el, on_el) :
26399 var autoToken = /\s?auto?\s?/i;
26400 var autoPlace = autoToken.test(placement);
26402 placement = placement.replace(autoToken, '') || 'top';
26406 //this.el.setXY([0,0]);
26408 //this.el.dom.style.display='block';
26410 //this.el.appendTo(on_el);
26412 var p = this.getPosition();
26413 var box = this.el.getBox();
26419 var align = this.alignment[placement];
26421 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26423 if(placement == 'top' || placement == 'bottom'){
26425 placement = 'right';
26428 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26429 placement = 'left';
26432 var scroll = Roo.select('body', true).first().getScroll();
26434 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26438 align = this.alignment[placement];
26441 this.el.alignTo(this.bindEl, align[0],align[1]);
26442 //var arrow = this.el.select('.arrow',true).first();
26443 //arrow.set(align[2],
26445 this.el.addClass(placement);
26447 this.el.addClass('in fade');
26449 this.hoverState = null;
26451 if (this.el.hasClass('fade')) {
26462 //this.el.setXY([0,0]);
26463 this.el.removeClass('in');
26479 * @class Roo.bootstrap.LocationPicker
26480 * @extends Roo.bootstrap.Component
26481 * Bootstrap LocationPicker class
26482 * @cfg {Number} latitude Position when init default 0
26483 * @cfg {Number} longitude Position when init default 0
26484 * @cfg {Number} zoom default 15
26485 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26486 * @cfg {Boolean} mapTypeControl default false
26487 * @cfg {Boolean} disableDoubleClickZoom default false
26488 * @cfg {Boolean} scrollwheel default true
26489 * @cfg {Boolean} streetViewControl default false
26490 * @cfg {Number} radius default 0
26491 * @cfg {String} locationName
26492 * @cfg {Boolean} draggable default true
26493 * @cfg {Boolean} enableAutocomplete default false
26494 * @cfg {Boolean} enableReverseGeocode default true
26495 * @cfg {String} markerTitle
26498 * Create a new LocationPicker
26499 * @param {Object} config The config object
26503 Roo.bootstrap.LocationPicker = function(config){
26505 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26510 * Fires when the picker initialized.
26511 * @param {Roo.bootstrap.LocationPicker} this
26512 * @param {Google Location} location
26516 * @event positionchanged
26517 * Fires when the picker position changed.
26518 * @param {Roo.bootstrap.LocationPicker} this
26519 * @param {Google Location} location
26521 positionchanged : true,
26524 * Fires when the map resize.
26525 * @param {Roo.bootstrap.LocationPicker} this
26530 * Fires when the map show.
26531 * @param {Roo.bootstrap.LocationPicker} this
26536 * Fires when the map hide.
26537 * @param {Roo.bootstrap.LocationPicker} this
26542 * Fires when click the map.
26543 * @param {Roo.bootstrap.LocationPicker} this
26544 * @param {Map event} e
26548 * @event mapRightClick
26549 * Fires when right click the map.
26550 * @param {Roo.bootstrap.LocationPicker} this
26551 * @param {Map event} e
26553 mapRightClick : true,
26555 * @event markerClick
26556 * Fires when click the marker.
26557 * @param {Roo.bootstrap.LocationPicker} this
26558 * @param {Map event} e
26560 markerClick : true,
26562 * @event markerRightClick
26563 * Fires when right click the marker.
26564 * @param {Roo.bootstrap.LocationPicker} this
26565 * @param {Map event} e
26567 markerRightClick : true,
26569 * @event OverlayViewDraw
26570 * Fires when OverlayView Draw
26571 * @param {Roo.bootstrap.LocationPicker} this
26573 OverlayViewDraw : true,
26575 * @event OverlayViewOnAdd
26576 * Fires when OverlayView Draw
26577 * @param {Roo.bootstrap.LocationPicker} this
26579 OverlayViewOnAdd : true,
26581 * @event OverlayViewOnRemove
26582 * Fires when OverlayView Draw
26583 * @param {Roo.bootstrap.LocationPicker} this
26585 OverlayViewOnRemove : true,
26587 * @event OverlayViewShow
26588 * Fires when OverlayView Draw
26589 * @param {Roo.bootstrap.LocationPicker} this
26590 * @param {Pixel} cpx
26592 OverlayViewShow : true,
26594 * @event OverlayViewHide
26595 * Fires when OverlayView Draw
26596 * @param {Roo.bootstrap.LocationPicker} this
26598 OverlayViewHide : true,
26600 * @event loadexception
26601 * Fires when load google lib failed.
26602 * @param {Roo.bootstrap.LocationPicker} this
26604 loadexception : true
26609 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26611 gMapContext: false,
26617 mapTypeControl: false,
26618 disableDoubleClickZoom: false,
26620 streetViewControl: false,
26624 enableAutocomplete: false,
26625 enableReverseGeocode: true,
26628 getAutoCreate: function()
26633 cls: 'roo-location-picker'
26639 initEvents: function(ct, position)
26641 if(!this.el.getWidth() || this.isApplied()){
26645 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26650 initial: function()
26652 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26653 this.fireEvent('loadexception', this);
26657 if(!this.mapTypeId){
26658 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26661 this.gMapContext = this.GMapContext();
26663 this.initOverlayView();
26665 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26669 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26670 _this.setPosition(_this.gMapContext.marker.position);
26673 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26674 _this.fireEvent('mapClick', this, event);
26678 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26679 _this.fireEvent('mapRightClick', this, event);
26683 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26684 _this.fireEvent('markerClick', this, event);
26688 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26689 _this.fireEvent('markerRightClick', this, event);
26693 this.setPosition(this.gMapContext.location);
26695 this.fireEvent('initial', this, this.gMapContext.location);
26698 initOverlayView: function()
26702 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26706 _this.fireEvent('OverlayViewDraw', _this);
26711 _this.fireEvent('OverlayViewOnAdd', _this);
26714 onRemove: function()
26716 _this.fireEvent('OverlayViewOnRemove', _this);
26719 show: function(cpx)
26721 _this.fireEvent('OverlayViewShow', _this, cpx);
26726 _this.fireEvent('OverlayViewHide', _this);
26732 fromLatLngToContainerPixel: function(event)
26734 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26737 isApplied: function()
26739 return this.getGmapContext() == false ? false : true;
26742 getGmapContext: function()
26744 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26747 GMapContext: function()
26749 var position = new google.maps.LatLng(this.latitude, this.longitude);
26751 var _map = new google.maps.Map(this.el.dom, {
26754 mapTypeId: this.mapTypeId,
26755 mapTypeControl: this.mapTypeControl,
26756 disableDoubleClickZoom: this.disableDoubleClickZoom,
26757 scrollwheel: this.scrollwheel,
26758 streetViewControl: this.streetViewControl,
26759 locationName: this.locationName,
26760 draggable: this.draggable,
26761 enableAutocomplete: this.enableAutocomplete,
26762 enableReverseGeocode: this.enableReverseGeocode
26765 var _marker = new google.maps.Marker({
26766 position: position,
26768 title: this.markerTitle,
26769 draggable: this.draggable
26776 location: position,
26777 radius: this.radius,
26778 locationName: this.locationName,
26779 addressComponents: {
26780 formatted_address: null,
26781 addressLine1: null,
26782 addressLine2: null,
26784 streetNumber: null,
26788 stateOrProvince: null
26791 domContainer: this.el.dom,
26792 geodecoder: new google.maps.Geocoder()
26796 drawCircle: function(center, radius, options)
26798 if (this.gMapContext.circle != null) {
26799 this.gMapContext.circle.setMap(null);
26803 options = Roo.apply({}, options, {
26804 strokeColor: "#0000FF",
26805 strokeOpacity: .35,
26807 fillColor: "#0000FF",
26811 options.map = this.gMapContext.map;
26812 options.radius = radius;
26813 options.center = center;
26814 this.gMapContext.circle = new google.maps.Circle(options);
26815 return this.gMapContext.circle;
26821 setPosition: function(location)
26823 this.gMapContext.location = location;
26824 this.gMapContext.marker.setPosition(location);
26825 this.gMapContext.map.panTo(location);
26826 this.drawCircle(location, this.gMapContext.radius, {});
26830 if (this.gMapContext.settings.enableReverseGeocode) {
26831 this.gMapContext.geodecoder.geocode({
26832 latLng: this.gMapContext.location
26833 }, function(results, status) {
26835 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26836 _this.gMapContext.locationName = results[0].formatted_address;
26837 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26839 _this.fireEvent('positionchanged', this, location);
26846 this.fireEvent('positionchanged', this, location);
26851 google.maps.event.trigger(this.gMapContext.map, "resize");
26853 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26855 this.fireEvent('resize', this);
26858 setPositionByLatLng: function(latitude, longitude)
26860 this.setPosition(new google.maps.LatLng(latitude, longitude));
26863 getCurrentPosition: function()
26866 latitude: this.gMapContext.location.lat(),
26867 longitude: this.gMapContext.location.lng()
26871 getAddressName: function()
26873 return this.gMapContext.locationName;
26876 getAddressComponents: function()
26878 return this.gMapContext.addressComponents;
26881 address_component_from_google_geocode: function(address_components)
26885 for (var i = 0; i < address_components.length; i++) {
26886 var component = address_components[i];
26887 if (component.types.indexOf("postal_code") >= 0) {
26888 result.postalCode = component.short_name;
26889 } else if (component.types.indexOf("street_number") >= 0) {
26890 result.streetNumber = component.short_name;
26891 } else if (component.types.indexOf("route") >= 0) {
26892 result.streetName = component.short_name;
26893 } else if (component.types.indexOf("neighborhood") >= 0) {
26894 result.city = component.short_name;
26895 } else if (component.types.indexOf("locality") >= 0) {
26896 result.city = component.short_name;
26897 } else if (component.types.indexOf("sublocality") >= 0) {
26898 result.district = component.short_name;
26899 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26900 result.stateOrProvince = component.short_name;
26901 } else if (component.types.indexOf("country") >= 0) {
26902 result.country = component.short_name;
26906 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26907 result.addressLine2 = "";
26911 setZoomLevel: function(zoom)
26913 this.gMapContext.map.setZoom(zoom);
26926 this.fireEvent('show', this);
26937 this.fireEvent('hide', this);
26942 Roo.apply(Roo.bootstrap.LocationPicker, {
26944 OverlayView : function(map, options)
26946 options = options || {};
26960 * @class Roo.bootstrap.Alert
26961 * @extends Roo.bootstrap.Component
26962 * Bootstrap Alert class
26963 * @cfg {String} title The title of alert
26964 * @cfg {String} html The content of alert
26965 * @cfg {String} weight ( success | info | warning | danger )
26966 * @cfg {String} faicon font-awesomeicon
26969 * Create a new alert
26970 * @param {Object} config The config object
26974 Roo.bootstrap.Alert = function(config){
26975 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26979 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
26986 getAutoCreate : function()
26995 cls : 'roo-alert-icon'
27000 cls : 'roo-alert-title',
27005 cls : 'roo-alert-text',
27012 cfg.cn[0].cls += ' fa ' + this.faicon;
27016 cfg.cls += ' alert-' + this.weight;
27022 initEvents: function()
27024 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27027 setTitle : function(str)
27029 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27032 setText : function(str)
27034 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27037 setWeight : function(weight)
27040 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27043 this.weight = weight;
27045 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27048 setIcon : function(icon)
27051 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27054 this.faicon = icon;
27056 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27077 * @class Roo.bootstrap.UploadCropbox
27078 * @extends Roo.bootstrap.Component
27079 * Bootstrap UploadCropbox class
27080 * @cfg {String} emptyText show when image has been loaded
27081 * @cfg {String} rotateNotify show when image too small to rotate
27082 * @cfg {Number} errorTimeout default 3000
27083 * @cfg {Number} minWidth default 300
27084 * @cfg {Number} minHeight default 300
27085 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27086 * @cfg {Boolean} isDocument (true|false) default false
27087 * @cfg {String} url action url
27088 * @cfg {String} paramName default 'imageUpload'
27089 * @cfg {String} method default POST
27090 * @cfg {Boolean} loadMask (true|false) default true
27091 * @cfg {Boolean} loadingText default 'Loading...'
27094 * Create a new UploadCropbox
27095 * @param {Object} config The config object
27098 Roo.bootstrap.UploadCropbox = function(config){
27099 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27103 * @event beforeselectfile
27104 * Fire before select file
27105 * @param {Roo.bootstrap.UploadCropbox} this
27107 "beforeselectfile" : true,
27110 * Fire after initEvent
27111 * @param {Roo.bootstrap.UploadCropbox} this
27116 * Fire after initEvent
27117 * @param {Roo.bootstrap.UploadCropbox} this
27118 * @param {String} data
27123 * Fire when preparing the file data
27124 * @param {Roo.bootstrap.UploadCropbox} this
27125 * @param {Object} file
27130 * Fire when get exception
27131 * @param {Roo.bootstrap.UploadCropbox} this
27132 * @param {XMLHttpRequest} xhr
27134 "exception" : true,
27136 * @event beforeloadcanvas
27137 * Fire before load the canvas
27138 * @param {Roo.bootstrap.UploadCropbox} this
27139 * @param {String} src
27141 "beforeloadcanvas" : true,
27144 * Fire when trash image
27145 * @param {Roo.bootstrap.UploadCropbox} this
27150 * Fire when download the image
27151 * @param {Roo.bootstrap.UploadCropbox} this
27155 * @event footerbuttonclick
27156 * Fire when footerbuttonclick
27157 * @param {Roo.bootstrap.UploadCropbox} this
27158 * @param {String} type
27160 "footerbuttonclick" : true,
27164 * @param {Roo.bootstrap.UploadCropbox} this
27169 * Fire when rotate the image
27170 * @param {Roo.bootstrap.UploadCropbox} this
27171 * @param {String} pos
27176 * Fire when inspect the file
27177 * @param {Roo.bootstrap.UploadCropbox} this
27178 * @param {Object} file
27183 * Fire when xhr upload the file
27184 * @param {Roo.bootstrap.UploadCropbox} this
27185 * @param {Object} data
27190 * Fire when arrange the file data
27191 * @param {Roo.bootstrap.UploadCropbox} this
27192 * @param {Object} formData
27197 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27200 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27202 emptyText : 'Click to upload image',
27203 rotateNotify : 'Image is too small to rotate',
27204 errorTimeout : 3000,
27218 cropType : 'image/jpeg',
27220 canvasLoaded : false,
27221 isDocument : false,
27223 paramName : 'imageUpload',
27225 loadingText : 'Loading...',
27228 getAutoCreate : function()
27232 cls : 'roo-upload-cropbox',
27236 cls : 'roo-upload-cropbox-selector',
27241 cls : 'roo-upload-cropbox-body',
27242 style : 'cursor:pointer',
27246 cls : 'roo-upload-cropbox-preview'
27250 cls : 'roo-upload-cropbox-thumb'
27254 cls : 'roo-upload-cropbox-empty-notify',
27255 html : this.emptyText
27259 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27260 html : this.rotateNotify
27266 cls : 'roo-upload-cropbox-footer',
27269 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27279 onRender : function(ct, position)
27281 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27283 if (this.buttons.length) {
27285 Roo.each(this.buttons, function(bb) {
27287 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27289 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27295 this.maskEl = this.el;
27299 initEvents : function()
27301 this.urlAPI = (window.createObjectURL && window) ||
27302 (window.URL && URL.revokeObjectURL && URL) ||
27303 (window.webkitURL && webkitURL);
27305 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27306 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27308 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27309 this.selectorEl.hide();
27311 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27312 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27314 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27315 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27316 this.thumbEl.hide();
27318 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27319 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27321 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27322 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27323 this.errorEl.hide();
27325 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27326 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27327 this.footerEl.hide();
27329 this.setThumbBoxSize();
27335 this.fireEvent('initial', this);
27342 window.addEventListener("resize", function() { _this.resize(); } );
27344 this.bodyEl.on('click', this.beforeSelectFile, this);
27347 this.bodyEl.on('touchstart', this.onTouchStart, this);
27348 this.bodyEl.on('touchmove', this.onTouchMove, this);
27349 this.bodyEl.on('touchend', this.onTouchEnd, this);
27353 this.bodyEl.on('mousedown', this.onMouseDown, this);
27354 this.bodyEl.on('mousemove', this.onMouseMove, this);
27355 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27356 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27357 Roo.get(document).on('mouseup', this.onMouseUp, this);
27360 this.selectorEl.on('change', this.onFileSelected, this);
27366 this.baseScale = 1;
27368 this.baseRotate = 1;
27369 this.dragable = false;
27370 this.pinching = false;
27373 this.cropData = false;
27374 this.notifyEl.dom.innerHTML = this.emptyText;
27376 this.selectorEl.dom.value = '';
27380 resize : function()
27382 if(this.fireEvent('resize', this) != false){
27383 this.setThumbBoxPosition();
27384 this.setCanvasPosition();
27388 onFooterButtonClick : function(e, el, o, type)
27391 case 'rotate-left' :
27392 this.onRotateLeft(e);
27394 case 'rotate-right' :
27395 this.onRotateRight(e);
27398 this.beforeSelectFile(e);
27413 this.fireEvent('footerbuttonclick', this, type);
27416 beforeSelectFile : function(e)
27418 e.preventDefault();
27420 if(this.fireEvent('beforeselectfile', this) != false){
27421 this.selectorEl.dom.click();
27425 onFileSelected : function(e)
27427 e.preventDefault();
27429 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27433 var file = this.selectorEl.dom.files[0];
27435 if(this.fireEvent('inspect', this, file) != false){
27436 this.prepare(file);
27441 trash : function(e)
27443 this.fireEvent('trash', this);
27446 download : function(e)
27448 this.fireEvent('download', this);
27451 loadCanvas : function(src)
27453 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27457 this.imageEl = document.createElement('img');
27461 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27463 this.imageEl.src = src;
27467 onLoadCanvas : function()
27469 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27470 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27472 this.bodyEl.un('click', this.beforeSelectFile, this);
27474 this.notifyEl.hide();
27475 this.thumbEl.show();
27476 this.footerEl.show();
27478 this.baseRotateLevel();
27480 if(this.isDocument){
27481 this.setThumbBoxSize();
27484 this.setThumbBoxPosition();
27486 this.baseScaleLevel();
27492 this.canvasLoaded = true;
27495 this.maskEl.unmask();
27500 setCanvasPosition : function()
27502 if(!this.canvasEl){
27506 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27507 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27509 this.previewEl.setLeft(pw);
27510 this.previewEl.setTop(ph);
27514 onMouseDown : function(e)
27518 this.dragable = true;
27519 this.pinching = false;
27521 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27522 this.dragable = false;
27526 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27527 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27531 onMouseMove : function(e)
27535 if(!this.canvasLoaded){
27539 if (!this.dragable){
27543 var minX = Math.ceil(this.thumbEl.getLeft(true));
27544 var minY = Math.ceil(this.thumbEl.getTop(true));
27546 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27547 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27549 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27550 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27552 x = x - this.mouseX;
27553 y = y - this.mouseY;
27555 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27556 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27558 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27559 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27561 this.previewEl.setLeft(bgX);
27562 this.previewEl.setTop(bgY);
27564 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27565 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27568 onMouseUp : function(e)
27572 this.dragable = false;
27575 onMouseWheel : function(e)
27579 this.startScale = this.scale;
27581 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27583 if(!this.zoomable()){
27584 this.scale = this.startScale;
27593 zoomable : function()
27595 var minScale = this.thumbEl.getWidth() / this.minWidth;
27597 if(this.minWidth < this.minHeight){
27598 minScale = this.thumbEl.getHeight() / this.minHeight;
27601 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27602 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27606 (this.rotate == 0 || this.rotate == 180) &&
27608 width > this.imageEl.OriginWidth ||
27609 height > this.imageEl.OriginHeight ||
27610 (width < this.minWidth && height < this.minHeight)
27618 (this.rotate == 90 || this.rotate == 270) &&
27620 width > this.imageEl.OriginWidth ||
27621 height > this.imageEl.OriginHeight ||
27622 (width < this.minHeight && height < this.minWidth)
27629 !this.isDocument &&
27630 (this.rotate == 0 || this.rotate == 180) &&
27632 width < this.minWidth ||
27633 width > this.imageEl.OriginWidth ||
27634 height < this.minHeight ||
27635 height > this.imageEl.OriginHeight
27642 !this.isDocument &&
27643 (this.rotate == 90 || this.rotate == 270) &&
27645 width < this.minHeight ||
27646 width > this.imageEl.OriginWidth ||
27647 height < this.minWidth ||
27648 height > this.imageEl.OriginHeight
27658 onRotateLeft : function(e)
27660 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27662 var minScale = this.thumbEl.getWidth() / this.minWidth;
27664 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27665 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27667 this.startScale = this.scale;
27669 while (this.getScaleLevel() < minScale){
27671 this.scale = this.scale + 1;
27673 if(!this.zoomable()){
27678 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27679 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27684 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27691 this.scale = this.startScale;
27693 this.onRotateFail();
27698 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27700 if(this.isDocument){
27701 this.setThumbBoxSize();
27702 this.setThumbBoxPosition();
27703 this.setCanvasPosition();
27708 this.fireEvent('rotate', this, 'left');
27712 onRotateRight : function(e)
27714 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27716 var minScale = this.thumbEl.getWidth() / this.minWidth;
27718 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27719 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27721 this.startScale = this.scale;
27723 while (this.getScaleLevel() < minScale){
27725 this.scale = this.scale + 1;
27727 if(!this.zoomable()){
27732 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27733 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27738 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27745 this.scale = this.startScale;
27747 this.onRotateFail();
27752 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27754 if(this.isDocument){
27755 this.setThumbBoxSize();
27756 this.setThumbBoxPosition();
27757 this.setCanvasPosition();
27762 this.fireEvent('rotate', this, 'right');
27765 onRotateFail : function()
27767 this.errorEl.show(true);
27771 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27776 this.previewEl.dom.innerHTML = '';
27778 var canvasEl = document.createElement("canvas");
27780 var contextEl = canvasEl.getContext("2d");
27782 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27783 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27784 var center = this.imageEl.OriginWidth / 2;
27786 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27787 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27788 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27789 center = this.imageEl.OriginHeight / 2;
27792 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27794 contextEl.translate(center, center);
27795 contextEl.rotate(this.rotate * Math.PI / 180);
27797 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27799 this.canvasEl = document.createElement("canvas");
27801 this.contextEl = this.canvasEl.getContext("2d");
27803 switch (this.rotate) {
27806 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27807 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27809 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27814 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27815 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27817 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27818 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);
27822 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27827 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27828 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27830 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27831 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);
27835 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);
27840 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27841 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27843 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27844 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27848 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);
27855 this.previewEl.appendChild(this.canvasEl);
27857 this.setCanvasPosition();
27862 if(!this.canvasLoaded){
27866 var imageCanvas = document.createElement("canvas");
27868 var imageContext = imageCanvas.getContext("2d");
27870 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27871 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27873 var center = imageCanvas.width / 2;
27875 imageContext.translate(center, center);
27877 imageContext.rotate(this.rotate * Math.PI / 180);
27879 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27881 var canvas = document.createElement("canvas");
27883 var context = canvas.getContext("2d");
27885 canvas.width = this.minWidth;
27886 canvas.height = this.minHeight;
27888 switch (this.rotate) {
27891 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27892 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27894 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27895 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27897 var targetWidth = this.minWidth - 2 * x;
27898 var targetHeight = this.minHeight - 2 * y;
27902 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27903 scale = targetWidth / width;
27906 if(x > 0 && y == 0){
27907 scale = targetHeight / height;
27910 if(x > 0 && y > 0){
27911 scale = targetWidth / width;
27913 if(width < height){
27914 scale = targetHeight / height;
27918 context.scale(scale, scale);
27920 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27921 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27923 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27924 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27926 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27931 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27932 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27934 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27935 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27937 var targetWidth = this.minWidth - 2 * x;
27938 var targetHeight = this.minHeight - 2 * y;
27942 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27943 scale = targetWidth / width;
27946 if(x > 0 && y == 0){
27947 scale = targetHeight / height;
27950 if(x > 0 && y > 0){
27951 scale = targetWidth / width;
27953 if(width < height){
27954 scale = targetHeight / height;
27958 context.scale(scale, scale);
27960 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27961 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27963 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27964 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27966 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27968 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27973 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27974 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27976 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27977 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27979 var targetWidth = this.minWidth - 2 * x;
27980 var targetHeight = this.minHeight - 2 * y;
27984 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27985 scale = targetWidth / width;
27988 if(x > 0 && y == 0){
27989 scale = targetHeight / height;
27992 if(x > 0 && y > 0){
27993 scale = targetWidth / width;
27995 if(width < height){
27996 scale = targetHeight / height;
28000 context.scale(scale, scale);
28002 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28003 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28005 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28006 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28008 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28009 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28011 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28016 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28017 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28019 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28020 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28022 var targetWidth = this.minWidth - 2 * x;
28023 var targetHeight = this.minHeight - 2 * y;
28027 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28028 scale = targetWidth / width;
28031 if(x > 0 && y == 0){
28032 scale = targetHeight / height;
28035 if(x > 0 && y > 0){
28036 scale = targetWidth / width;
28038 if(width < height){
28039 scale = targetHeight / height;
28043 context.scale(scale, scale);
28045 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28046 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28048 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28049 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28051 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28053 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28060 this.cropData = canvas.toDataURL(this.cropType);
28062 if(this.fireEvent('crop', this, this.cropData) !== false){
28063 this.process(this.file, this.cropData);
28070 setThumbBoxSize : function()
28074 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28075 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28076 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28078 this.minWidth = width;
28079 this.minHeight = height;
28081 if(this.rotate == 90 || this.rotate == 270){
28082 this.minWidth = height;
28083 this.minHeight = width;
28088 width = Math.ceil(this.minWidth * height / this.minHeight);
28090 if(this.minWidth > this.minHeight){
28092 height = Math.ceil(this.minHeight * width / this.minWidth);
28095 this.thumbEl.setStyle({
28096 width : width + 'px',
28097 height : height + 'px'
28104 setThumbBoxPosition : function()
28106 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28107 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28109 this.thumbEl.setLeft(x);
28110 this.thumbEl.setTop(y);
28114 baseRotateLevel : function()
28116 this.baseRotate = 1;
28119 typeof(this.exif) != 'undefined' &&
28120 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28121 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28123 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28126 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28130 baseScaleLevel : function()
28134 if(this.isDocument){
28136 if(this.baseRotate == 6 || this.baseRotate == 8){
28138 height = this.thumbEl.getHeight();
28139 this.baseScale = height / this.imageEl.OriginWidth;
28141 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28142 width = this.thumbEl.getWidth();
28143 this.baseScale = width / this.imageEl.OriginHeight;
28149 height = this.thumbEl.getHeight();
28150 this.baseScale = height / this.imageEl.OriginHeight;
28152 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28153 width = this.thumbEl.getWidth();
28154 this.baseScale = width / this.imageEl.OriginWidth;
28160 if(this.baseRotate == 6 || this.baseRotate == 8){
28162 width = this.thumbEl.getHeight();
28163 this.baseScale = width / this.imageEl.OriginHeight;
28165 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28166 height = this.thumbEl.getWidth();
28167 this.baseScale = height / this.imageEl.OriginHeight;
28170 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28171 height = this.thumbEl.getWidth();
28172 this.baseScale = height / this.imageEl.OriginHeight;
28174 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28175 width = this.thumbEl.getHeight();
28176 this.baseScale = width / this.imageEl.OriginWidth;
28183 width = this.thumbEl.getWidth();
28184 this.baseScale = width / this.imageEl.OriginWidth;
28186 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28187 height = this.thumbEl.getHeight();
28188 this.baseScale = height / this.imageEl.OriginHeight;
28191 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28193 height = this.thumbEl.getHeight();
28194 this.baseScale = height / this.imageEl.OriginHeight;
28196 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28197 width = this.thumbEl.getWidth();
28198 this.baseScale = width / this.imageEl.OriginWidth;
28206 getScaleLevel : function()
28208 return this.baseScale * Math.pow(1.1, this.scale);
28211 onTouchStart : function(e)
28213 if(!this.canvasLoaded){
28214 this.beforeSelectFile(e);
28218 var touches = e.browserEvent.touches;
28224 if(touches.length == 1){
28225 this.onMouseDown(e);
28229 if(touches.length != 2){
28235 for(var i = 0, finger; finger = touches[i]; i++){
28236 coords.push(finger.pageX, finger.pageY);
28239 var x = Math.pow(coords[0] - coords[2], 2);
28240 var y = Math.pow(coords[1] - coords[3], 2);
28242 this.startDistance = Math.sqrt(x + y);
28244 this.startScale = this.scale;
28246 this.pinching = true;
28247 this.dragable = false;
28251 onTouchMove : function(e)
28253 if(!this.pinching && !this.dragable){
28257 var touches = e.browserEvent.touches;
28264 this.onMouseMove(e);
28270 for(var i = 0, finger; finger = touches[i]; i++){
28271 coords.push(finger.pageX, finger.pageY);
28274 var x = Math.pow(coords[0] - coords[2], 2);
28275 var y = Math.pow(coords[1] - coords[3], 2);
28277 this.endDistance = Math.sqrt(x + y);
28279 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28281 if(!this.zoomable()){
28282 this.scale = this.startScale;
28290 onTouchEnd : function(e)
28292 this.pinching = false;
28293 this.dragable = false;
28297 process : function(file, crop)
28300 this.maskEl.mask(this.loadingText);
28303 this.xhr = new XMLHttpRequest();
28305 file.xhr = this.xhr;
28307 this.xhr.open(this.method, this.url, true);
28310 "Accept": "application/json",
28311 "Cache-Control": "no-cache",
28312 "X-Requested-With": "XMLHttpRequest"
28315 for (var headerName in headers) {
28316 var headerValue = headers[headerName];
28318 this.xhr.setRequestHeader(headerName, headerValue);
28324 this.xhr.onload = function()
28326 _this.xhrOnLoad(_this.xhr);
28329 this.xhr.onerror = function()
28331 _this.xhrOnError(_this.xhr);
28334 var formData = new FormData();
28336 formData.append('returnHTML', 'NO');
28339 formData.append('crop', crop);
28342 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28343 formData.append(this.paramName, file, file.name);
28346 if(typeof(file.filename) != 'undefined'){
28347 formData.append('filename', file.filename);
28350 if(typeof(file.mimetype) != 'undefined'){
28351 formData.append('mimetype', file.mimetype);
28354 if(this.fireEvent('arrange', this, formData) != false){
28355 this.xhr.send(formData);
28359 xhrOnLoad : function(xhr)
28362 this.maskEl.unmask();
28365 if (xhr.readyState !== 4) {
28366 this.fireEvent('exception', this, xhr);
28370 var response = Roo.decode(xhr.responseText);
28372 if(!response.success){
28373 this.fireEvent('exception', this, xhr);
28377 var response = Roo.decode(xhr.responseText);
28379 this.fireEvent('upload', this, response);
28383 xhrOnError : function()
28386 this.maskEl.unmask();
28389 Roo.log('xhr on error');
28391 var response = Roo.decode(xhr.responseText);
28397 prepare : function(file)
28400 this.maskEl.mask(this.loadingText);
28406 if(typeof(file) === 'string'){
28407 this.loadCanvas(file);
28411 if(!file || !this.urlAPI){
28416 this.cropType = file.type;
28420 if(this.fireEvent('prepare', this, this.file) != false){
28422 var reader = new FileReader();
28424 reader.onload = function (e) {
28425 if (e.target.error) {
28426 Roo.log(e.target.error);
28430 var buffer = e.target.result,
28431 dataView = new DataView(buffer),
28433 maxOffset = dataView.byteLength - 4,
28437 if (dataView.getUint16(0) === 0xffd8) {
28438 while (offset < maxOffset) {
28439 markerBytes = dataView.getUint16(offset);
28441 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28442 markerLength = dataView.getUint16(offset + 2) + 2;
28443 if (offset + markerLength > dataView.byteLength) {
28444 Roo.log('Invalid meta data: Invalid segment size.');
28448 if(markerBytes == 0xffe1){
28449 _this.parseExifData(
28456 offset += markerLength;
28466 var url = _this.urlAPI.createObjectURL(_this.file);
28468 _this.loadCanvas(url);
28473 reader.readAsArrayBuffer(this.file);
28479 parseExifData : function(dataView, offset, length)
28481 var tiffOffset = offset + 10,
28485 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28486 // No Exif data, might be XMP data instead
28490 // Check for the ASCII code for "Exif" (0x45786966):
28491 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28492 // No Exif data, might be XMP data instead
28495 if (tiffOffset + 8 > dataView.byteLength) {
28496 Roo.log('Invalid Exif data: Invalid segment size.');
28499 // Check for the two null bytes:
28500 if (dataView.getUint16(offset + 8) !== 0x0000) {
28501 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28504 // Check the byte alignment:
28505 switch (dataView.getUint16(tiffOffset)) {
28507 littleEndian = true;
28510 littleEndian = false;
28513 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28516 // Check for the TIFF tag marker (0x002A):
28517 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28518 Roo.log('Invalid Exif data: Missing TIFF marker.');
28521 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28522 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28524 this.parseExifTags(
28527 tiffOffset + dirOffset,
28532 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28537 if (dirOffset + 6 > dataView.byteLength) {
28538 Roo.log('Invalid Exif data: Invalid directory offset.');
28541 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28542 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28543 if (dirEndOffset + 4 > dataView.byteLength) {
28544 Roo.log('Invalid Exif data: Invalid directory size.');
28547 for (i = 0; i < tagsNumber; i += 1) {
28551 dirOffset + 2 + 12 * i, // tag offset
28555 // Return the offset to the next directory:
28556 return dataView.getUint32(dirEndOffset, littleEndian);
28559 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28561 var tag = dataView.getUint16(offset, littleEndian);
28563 this.exif[tag] = this.getExifValue(
28567 dataView.getUint16(offset + 2, littleEndian), // tag type
28568 dataView.getUint32(offset + 4, littleEndian), // tag length
28573 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28575 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28584 Roo.log('Invalid Exif data: Invalid tag type.');
28588 tagSize = tagType.size * length;
28589 // Determine if the value is contained in the dataOffset bytes,
28590 // or if the value at the dataOffset is a pointer to the actual data:
28591 dataOffset = tagSize > 4 ?
28592 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28593 if (dataOffset + tagSize > dataView.byteLength) {
28594 Roo.log('Invalid Exif data: Invalid data offset.');
28597 if (length === 1) {
28598 return tagType.getValue(dataView, dataOffset, littleEndian);
28601 for (i = 0; i < length; i += 1) {
28602 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28605 if (tagType.ascii) {
28607 // Concatenate the chars:
28608 for (i = 0; i < values.length; i += 1) {
28610 // Ignore the terminating NULL byte(s):
28611 if (c === '\u0000') {
28623 Roo.apply(Roo.bootstrap.UploadCropbox, {
28625 'Orientation': 0x0112
28629 1: 0, //'top-left',
28631 3: 180, //'bottom-right',
28632 // 4: 'bottom-left',
28634 6: 90, //'right-top',
28635 // 7: 'right-bottom',
28636 8: 270 //'left-bottom'
28640 // byte, 8-bit unsigned int:
28642 getValue: function (dataView, dataOffset) {
28643 return dataView.getUint8(dataOffset);
28647 // ascii, 8-bit byte:
28649 getValue: function (dataView, dataOffset) {
28650 return String.fromCharCode(dataView.getUint8(dataOffset));
28655 // short, 16 bit int:
28657 getValue: function (dataView, dataOffset, littleEndian) {
28658 return dataView.getUint16(dataOffset, littleEndian);
28662 // long, 32 bit int:
28664 getValue: function (dataView, dataOffset, littleEndian) {
28665 return dataView.getUint32(dataOffset, littleEndian);
28669 // rational = two long values, first is numerator, second is denominator:
28671 getValue: function (dataView, dataOffset, littleEndian) {
28672 return dataView.getUint32(dataOffset, littleEndian) /
28673 dataView.getUint32(dataOffset + 4, littleEndian);
28677 // slong, 32 bit signed int:
28679 getValue: function (dataView, dataOffset, littleEndian) {
28680 return dataView.getInt32(dataOffset, littleEndian);
28684 // srational, two slongs, first is numerator, second is denominator:
28686 getValue: function (dataView, dataOffset, littleEndian) {
28687 return dataView.getInt32(dataOffset, littleEndian) /
28688 dataView.getInt32(dataOffset + 4, littleEndian);
28698 cls : 'btn-group roo-upload-cropbox-rotate-left',
28699 action : 'rotate-left',
28703 cls : 'btn btn-default',
28704 html : '<i class="fa fa-undo"></i>'
28710 cls : 'btn-group roo-upload-cropbox-picture',
28711 action : 'picture',
28715 cls : 'btn btn-default',
28716 html : '<i class="fa fa-picture-o"></i>'
28722 cls : 'btn-group roo-upload-cropbox-rotate-right',
28723 action : 'rotate-right',
28727 cls : 'btn btn-default',
28728 html : '<i class="fa fa-repeat"></i>'
28736 cls : 'btn-group roo-upload-cropbox-rotate-left',
28737 action : 'rotate-left',
28741 cls : 'btn btn-default',
28742 html : '<i class="fa fa-undo"></i>'
28748 cls : 'btn-group roo-upload-cropbox-download',
28749 action : 'download',
28753 cls : 'btn btn-default',
28754 html : '<i class="fa fa-download"></i>'
28760 cls : 'btn-group roo-upload-cropbox-crop',
28765 cls : 'btn btn-default',
28766 html : '<i class="fa fa-crop"></i>'
28772 cls : 'btn-group roo-upload-cropbox-trash',
28777 cls : 'btn btn-default',
28778 html : '<i class="fa fa-trash"></i>'
28784 cls : 'btn-group roo-upload-cropbox-rotate-right',
28785 action : 'rotate-right',
28789 cls : 'btn btn-default',
28790 html : '<i class="fa fa-repeat"></i>'
28798 cls : 'btn-group roo-upload-cropbox-rotate-left',
28799 action : 'rotate-left',
28803 cls : 'btn btn-default',
28804 html : '<i class="fa fa-undo"></i>'
28810 cls : 'btn-group roo-upload-cropbox-rotate-right',
28811 action : 'rotate-right',
28815 cls : 'btn btn-default',
28816 html : '<i class="fa fa-repeat"></i>'
28829 * @class Roo.bootstrap.DocumentManager
28830 * @extends Roo.bootstrap.Component
28831 * Bootstrap DocumentManager class
28832 * @cfg {String} paramName default 'imageUpload'
28833 * @cfg {String} toolTipName default 'filename'
28834 * @cfg {String} method default POST
28835 * @cfg {String} url action url
28836 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28837 * @cfg {Boolean} multiple multiple upload default true
28838 * @cfg {Number} thumbSize default 300
28839 * @cfg {String} fieldLabel
28840 * @cfg {Number} labelWidth default 4
28841 * @cfg {String} labelAlign (left|top) default left
28842 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28843 * @cfg {Number} labellg set the width of label (1-12)
28844 * @cfg {Number} labelmd set the width of label (1-12)
28845 * @cfg {Number} labelsm set the width of label (1-12)
28846 * @cfg {Number} labelxs set the width of label (1-12)
28849 * Create a new DocumentManager
28850 * @param {Object} config The config object
28853 Roo.bootstrap.DocumentManager = function(config){
28854 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28857 this.delegates = [];
28862 * Fire when initial the DocumentManager
28863 * @param {Roo.bootstrap.DocumentManager} this
28868 * inspect selected file
28869 * @param {Roo.bootstrap.DocumentManager} this
28870 * @param {File} file
28875 * Fire when xhr load exception
28876 * @param {Roo.bootstrap.DocumentManager} this
28877 * @param {XMLHttpRequest} xhr
28879 "exception" : true,
28881 * @event afterupload
28882 * Fire when xhr load exception
28883 * @param {Roo.bootstrap.DocumentManager} this
28884 * @param {XMLHttpRequest} xhr
28886 "afterupload" : true,
28889 * prepare the form data
28890 * @param {Roo.bootstrap.DocumentManager} this
28891 * @param {Object} formData
28896 * Fire when remove the file
28897 * @param {Roo.bootstrap.DocumentManager} this
28898 * @param {Object} file
28903 * Fire after refresh the file
28904 * @param {Roo.bootstrap.DocumentManager} this
28909 * Fire after click the image
28910 * @param {Roo.bootstrap.DocumentManager} this
28911 * @param {Object} file
28916 * Fire when upload a image and editable set to true
28917 * @param {Roo.bootstrap.DocumentManager} this
28918 * @param {Object} file
28922 * @event beforeselectfile
28923 * Fire before select file
28924 * @param {Roo.bootstrap.DocumentManager} this
28926 "beforeselectfile" : true,
28929 * Fire before process file
28930 * @param {Roo.bootstrap.DocumentManager} this
28931 * @param {Object} file
28935 * @event previewrendered
28936 * Fire when preview rendered
28937 * @param {Roo.bootstrap.DocumentManager} this
28938 * @param {Object} file
28940 "previewrendered" : true,
28943 "previewResize" : true
28948 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28957 paramName : 'imageUpload',
28958 toolTipName : 'filename',
28961 labelAlign : 'left',
28971 getAutoCreate : function()
28973 var managerWidget = {
28975 cls : 'roo-document-manager',
28979 cls : 'roo-document-manager-selector',
28984 cls : 'roo-document-manager-uploader',
28988 cls : 'roo-document-manager-upload-btn',
28989 html : '<i class="fa fa-plus"></i>'
29000 cls : 'column col-md-12',
29005 if(this.fieldLabel.length){
29010 cls : 'column col-md-12',
29011 html : this.fieldLabel
29015 cls : 'column col-md-12',
29020 if(this.labelAlign == 'left'){
29025 html : this.fieldLabel
29034 if(this.labelWidth > 12){
29035 content[0].style = "width: " + this.labelWidth + 'px';
29038 if(this.labelWidth < 13 && this.labelmd == 0){
29039 this.labelmd = this.labelWidth;
29042 if(this.labellg > 0){
29043 content[0].cls += ' col-lg-' + this.labellg;
29044 content[1].cls += ' col-lg-' + (12 - this.labellg);
29047 if(this.labelmd > 0){
29048 content[0].cls += ' col-md-' + this.labelmd;
29049 content[1].cls += ' col-md-' + (12 - this.labelmd);
29052 if(this.labelsm > 0){
29053 content[0].cls += ' col-sm-' + this.labelsm;
29054 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29057 if(this.labelxs > 0){
29058 content[0].cls += ' col-xs-' + this.labelxs;
29059 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29067 cls : 'row clearfix',
29075 initEvents : function()
29077 this.managerEl = this.el.select('.roo-document-manager', true).first();
29078 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29080 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29081 this.selectorEl.hide();
29084 this.selectorEl.attr('multiple', 'multiple');
29087 this.selectorEl.on('change', this.onFileSelected, this);
29089 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29090 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29092 this.uploader.on('click', this.onUploaderClick, this);
29094 this.renderProgressDialog();
29098 window.addEventListener("resize", function() { _this.refresh(); } );
29100 this.fireEvent('initial', this);
29103 renderProgressDialog : function()
29107 this.progressDialog = new Roo.bootstrap.Modal({
29108 cls : 'roo-document-manager-progress-dialog',
29109 allow_close : false,
29119 btnclick : function() {
29120 _this.uploadCancel();
29126 this.progressDialog.render(Roo.get(document.body));
29128 this.progress = new Roo.bootstrap.Progress({
29129 cls : 'roo-document-manager-progress',
29134 this.progress.render(this.progressDialog.getChildContainer());
29136 this.progressBar = new Roo.bootstrap.ProgressBar({
29137 cls : 'roo-document-manager-progress-bar',
29140 aria_valuemax : 12,
29144 this.progressBar.render(this.progress.getChildContainer());
29147 onUploaderClick : function(e)
29149 e.preventDefault();
29151 if(this.fireEvent('beforeselectfile', this) != false){
29152 this.selectorEl.dom.click();
29157 onFileSelected : function(e)
29159 e.preventDefault();
29161 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29165 Roo.each(this.selectorEl.dom.files, function(file){
29166 if(this.fireEvent('inspect', this, file) != false){
29167 this.files.push(file);
29177 this.selectorEl.dom.value = '';
29179 if(!this.files || !this.files.length){
29183 if(this.boxes > 0 && this.files.length > this.boxes){
29184 this.files = this.files.slice(0, this.boxes);
29187 this.uploader.show();
29189 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29190 this.uploader.hide();
29199 Roo.each(this.files, function(file){
29201 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29202 var f = this.renderPreview(file);
29207 if(file.type.indexOf('image') != -1){
29208 this.delegates.push(
29210 _this.process(file);
29211 }).createDelegate(this)
29219 _this.process(file);
29220 }).createDelegate(this)
29225 this.files = files;
29227 this.delegates = this.delegates.concat(docs);
29229 if(!this.delegates.length){
29234 this.progressBar.aria_valuemax = this.delegates.length;
29241 arrange : function()
29243 if(!this.delegates.length){
29244 this.progressDialog.hide();
29249 var delegate = this.delegates.shift();
29251 this.progressDialog.show();
29253 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29255 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29260 refresh : function()
29262 this.uploader.show();
29264 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29265 this.uploader.hide();
29268 Roo.isTouch ? this.closable(false) : this.closable(true);
29270 this.fireEvent('refresh', this);
29273 onRemove : function(e, el, o)
29275 e.preventDefault();
29277 this.fireEvent('remove', this, o);
29281 remove : function(o)
29285 Roo.each(this.files, function(file){
29286 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29295 this.files = files;
29302 Roo.each(this.files, function(file){
29307 file.target.remove();
29316 onClick : function(e, el, o)
29318 e.preventDefault();
29320 this.fireEvent('click', this, o);
29324 closable : function(closable)
29326 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29328 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29340 xhrOnLoad : function(xhr)
29342 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29346 if (xhr.readyState !== 4) {
29348 this.fireEvent('exception', this, xhr);
29352 var response = Roo.decode(xhr.responseText);
29354 if(!response.success){
29356 this.fireEvent('exception', this, xhr);
29360 var file = this.renderPreview(response.data);
29362 this.files.push(file);
29366 this.fireEvent('afterupload', this, xhr);
29370 xhrOnError : function(xhr)
29372 Roo.log('xhr on error');
29374 var response = Roo.decode(xhr.responseText);
29381 process : function(file)
29383 if(this.fireEvent('process', this, file) !== false){
29384 if(this.editable && file.type.indexOf('image') != -1){
29385 this.fireEvent('edit', this, file);
29389 this.uploadStart(file, false);
29396 uploadStart : function(file, crop)
29398 this.xhr = new XMLHttpRequest();
29400 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29405 file.xhr = this.xhr;
29407 this.managerEl.createChild({
29409 cls : 'roo-document-manager-loading',
29413 tooltip : file.name,
29414 cls : 'roo-document-manager-thumb',
29415 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29421 this.xhr.open(this.method, this.url, true);
29424 "Accept": "application/json",
29425 "Cache-Control": "no-cache",
29426 "X-Requested-With": "XMLHttpRequest"
29429 for (var headerName in headers) {
29430 var headerValue = headers[headerName];
29432 this.xhr.setRequestHeader(headerName, headerValue);
29438 this.xhr.onload = function()
29440 _this.xhrOnLoad(_this.xhr);
29443 this.xhr.onerror = function()
29445 _this.xhrOnError(_this.xhr);
29448 var formData = new FormData();
29450 formData.append('returnHTML', 'NO');
29453 formData.append('crop', crop);
29456 formData.append(this.paramName, file, file.name);
29463 if(this.fireEvent('prepare', this, formData, options) != false){
29465 if(options.manually){
29469 this.xhr.send(formData);
29473 this.uploadCancel();
29476 uploadCancel : function()
29482 this.delegates = [];
29484 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29491 renderPreview : function(file)
29493 if(typeof(file.target) != 'undefined' && file.target){
29497 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29499 var previewEl = this.managerEl.createChild({
29501 cls : 'roo-document-manager-preview',
29505 tooltip : file[this.toolTipName],
29506 cls : 'roo-document-manager-thumb',
29507 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29512 html : '<i class="fa fa-times-circle"></i>'
29517 var close = previewEl.select('button.close', true).first();
29519 close.on('click', this.onRemove, this, file);
29521 file.target = previewEl;
29523 var image = previewEl.select('img', true).first();
29527 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29529 image.on('click', this.onClick, this, file);
29531 this.fireEvent('previewrendered', this, file);
29537 onPreviewLoad : function(file, image)
29539 if(typeof(file.target) == 'undefined' || !file.target){
29543 var width = image.dom.naturalWidth || image.dom.width;
29544 var height = image.dom.naturalHeight || image.dom.height;
29546 if(!this.previewResize) {
29550 if(width > height){
29551 file.target.addClass('wide');
29555 file.target.addClass('tall');
29560 uploadFromSource : function(file, crop)
29562 this.xhr = new XMLHttpRequest();
29564 this.managerEl.createChild({
29566 cls : 'roo-document-manager-loading',
29570 tooltip : file.name,
29571 cls : 'roo-document-manager-thumb',
29572 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29578 this.xhr.open(this.method, this.url, true);
29581 "Accept": "application/json",
29582 "Cache-Control": "no-cache",
29583 "X-Requested-With": "XMLHttpRequest"
29586 for (var headerName in headers) {
29587 var headerValue = headers[headerName];
29589 this.xhr.setRequestHeader(headerName, headerValue);
29595 this.xhr.onload = function()
29597 _this.xhrOnLoad(_this.xhr);
29600 this.xhr.onerror = function()
29602 _this.xhrOnError(_this.xhr);
29605 var formData = new FormData();
29607 formData.append('returnHTML', 'NO');
29609 formData.append('crop', crop);
29611 if(typeof(file.filename) != 'undefined'){
29612 formData.append('filename', file.filename);
29615 if(typeof(file.mimetype) != 'undefined'){
29616 formData.append('mimetype', file.mimetype);
29621 if(this.fireEvent('prepare', this, formData) != false){
29622 this.xhr.send(formData);
29632 * @class Roo.bootstrap.DocumentViewer
29633 * @extends Roo.bootstrap.Component
29634 * Bootstrap DocumentViewer class
29635 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29636 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29639 * Create a new DocumentViewer
29640 * @param {Object} config The config object
29643 Roo.bootstrap.DocumentViewer = function(config){
29644 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29649 * Fire after initEvent
29650 * @param {Roo.bootstrap.DocumentViewer} this
29656 * @param {Roo.bootstrap.DocumentViewer} this
29661 * Fire after download button
29662 * @param {Roo.bootstrap.DocumentViewer} this
29667 * Fire after trash button
29668 * @param {Roo.bootstrap.DocumentViewer} this
29675 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29677 showDownload : true,
29681 getAutoCreate : function()
29685 cls : 'roo-document-viewer',
29689 cls : 'roo-document-viewer-body',
29693 cls : 'roo-document-viewer-thumb',
29697 cls : 'roo-document-viewer-image'
29705 cls : 'roo-document-viewer-footer',
29708 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29712 cls : 'btn-group roo-document-viewer-download',
29716 cls : 'btn btn-default',
29717 html : '<i class="fa fa-download"></i>'
29723 cls : 'btn-group roo-document-viewer-trash',
29727 cls : 'btn btn-default',
29728 html : '<i class="fa fa-trash"></i>'
29741 initEvents : function()
29743 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29744 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29746 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29747 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29749 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29750 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29752 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29753 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29755 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29756 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29758 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29759 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29761 this.bodyEl.on('click', this.onClick, this);
29762 this.downloadBtn.on('click', this.onDownload, this);
29763 this.trashBtn.on('click', this.onTrash, this);
29765 this.downloadBtn.hide();
29766 this.trashBtn.hide();
29768 if(this.showDownload){
29769 this.downloadBtn.show();
29772 if(this.showTrash){
29773 this.trashBtn.show();
29776 if(!this.showDownload && !this.showTrash) {
29777 this.footerEl.hide();
29782 initial : function()
29784 this.fireEvent('initial', this);
29788 onClick : function(e)
29790 e.preventDefault();
29792 this.fireEvent('click', this);
29795 onDownload : function(e)
29797 e.preventDefault();
29799 this.fireEvent('download', this);
29802 onTrash : function(e)
29804 e.preventDefault();
29806 this.fireEvent('trash', this);
29818 * @class Roo.bootstrap.NavProgressBar
29819 * @extends Roo.bootstrap.Component
29820 * Bootstrap NavProgressBar class
29823 * Create a new nav progress bar
29824 * @param {Object} config The config object
29827 Roo.bootstrap.NavProgressBar = function(config){
29828 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29830 this.bullets = this.bullets || [];
29832 // Roo.bootstrap.NavProgressBar.register(this);
29836 * Fires when the active item changes
29837 * @param {Roo.bootstrap.NavProgressBar} this
29838 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29839 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29846 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29851 getAutoCreate : function()
29853 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29857 cls : 'roo-navigation-bar-group',
29861 cls : 'roo-navigation-top-bar'
29865 cls : 'roo-navigation-bullets-bar',
29869 cls : 'roo-navigation-bar'
29876 cls : 'roo-navigation-bottom-bar'
29886 initEvents: function()
29891 onRender : function(ct, position)
29893 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29895 if(this.bullets.length){
29896 Roo.each(this.bullets, function(b){
29905 addItem : function(cfg)
29907 var item = new Roo.bootstrap.NavProgressItem(cfg);
29909 item.parentId = this.id;
29910 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29913 var top = new Roo.bootstrap.Element({
29915 cls : 'roo-navigation-bar-text'
29918 var bottom = new Roo.bootstrap.Element({
29920 cls : 'roo-navigation-bar-text'
29923 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29924 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29926 var topText = new Roo.bootstrap.Element({
29928 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29931 var bottomText = new Roo.bootstrap.Element({
29933 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29936 topText.onRender(top.el, null);
29937 bottomText.onRender(bottom.el, null);
29940 item.bottomEl = bottom;
29943 this.barItems.push(item);
29948 getActive : function()
29950 var active = false;
29952 Roo.each(this.barItems, function(v){
29954 if (!v.isActive()) {
29966 setActiveItem : function(item)
29970 Roo.each(this.barItems, function(v){
29971 if (v.rid == item.rid) {
29975 if (v.isActive()) {
29976 v.setActive(false);
29981 item.setActive(true);
29983 this.fireEvent('changed', this, item, prev);
29986 getBarItem: function(rid)
29990 Roo.each(this.barItems, function(e) {
29991 if (e.rid != rid) {
30002 indexOfItem : function(item)
30006 Roo.each(this.barItems, function(v, i){
30008 if (v.rid != item.rid) {
30019 setActiveNext : function()
30021 var i = this.indexOfItem(this.getActive());
30023 if (i > this.barItems.length) {
30027 this.setActiveItem(this.barItems[i+1]);
30030 setActivePrev : function()
30032 var i = this.indexOfItem(this.getActive());
30038 this.setActiveItem(this.barItems[i-1]);
30041 format : function()
30043 if(!this.barItems.length){
30047 var width = 100 / this.barItems.length;
30049 Roo.each(this.barItems, function(i){
30050 i.el.setStyle('width', width + '%');
30051 i.topEl.el.setStyle('width', width + '%');
30052 i.bottomEl.el.setStyle('width', width + '%');
30061 * Nav Progress Item
30066 * @class Roo.bootstrap.NavProgressItem
30067 * @extends Roo.bootstrap.Component
30068 * Bootstrap NavProgressItem class
30069 * @cfg {String} rid the reference id
30070 * @cfg {Boolean} active (true|false) Is item active default false
30071 * @cfg {Boolean} disabled (true|false) Is item active default false
30072 * @cfg {String} html
30073 * @cfg {String} position (top|bottom) text position default bottom
30074 * @cfg {String} icon show icon instead of number
30077 * Create a new NavProgressItem
30078 * @param {Object} config The config object
30080 Roo.bootstrap.NavProgressItem = function(config){
30081 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30086 * The raw click event for the entire grid.
30087 * @param {Roo.bootstrap.NavProgressItem} this
30088 * @param {Roo.EventObject} e
30095 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30101 position : 'bottom',
30104 getAutoCreate : function()
30106 var iconCls = 'roo-navigation-bar-item-icon';
30108 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30112 cls: 'roo-navigation-bar-item',
30122 cfg.cls += ' active';
30125 cfg.cls += ' disabled';
30131 disable : function()
30133 this.setDisabled(true);
30136 enable : function()
30138 this.setDisabled(false);
30141 initEvents: function()
30143 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30145 this.iconEl.on('click', this.onClick, this);
30148 onClick : function(e)
30150 e.preventDefault();
30156 if(this.fireEvent('click', this, e) === false){
30160 this.parent().setActiveItem(this);
30163 isActive: function ()
30165 return this.active;
30168 setActive : function(state)
30170 if(this.active == state){
30174 this.active = state;
30177 this.el.addClass('active');
30181 this.el.removeClass('active');
30186 setDisabled : function(state)
30188 if(this.disabled == state){
30192 this.disabled = state;
30195 this.el.addClass('disabled');
30199 this.el.removeClass('disabled');
30202 tooltipEl : function()
30204 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30217 * @class Roo.bootstrap.FieldLabel
30218 * @extends Roo.bootstrap.Component
30219 * Bootstrap FieldLabel class
30220 * @cfg {String} html contents of the element
30221 * @cfg {String} tag tag of the element default label
30222 * @cfg {String} cls class of the element
30223 * @cfg {String} target label target
30224 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30225 * @cfg {String} invalidClass default "text-warning"
30226 * @cfg {String} validClass default "text-success"
30227 * @cfg {String} iconTooltip default "This field is required"
30228 * @cfg {String} indicatorpos (left|right) default left
30231 * Create a new FieldLabel
30232 * @param {Object} config The config object
30235 Roo.bootstrap.FieldLabel = function(config){
30236 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30241 * Fires after the field has been marked as invalid.
30242 * @param {Roo.form.FieldLabel} this
30243 * @param {String} msg The validation message
30248 * Fires after the field has been validated with no errors.
30249 * @param {Roo.form.FieldLabel} this
30255 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30262 invalidClass : 'has-warning',
30263 validClass : 'has-success',
30264 iconTooltip : 'This field is required',
30265 indicatorpos : 'left',
30267 getAutoCreate : function(){
30270 if (!this.allowBlank) {
30276 cls : 'roo-bootstrap-field-label ' + this.cls,
30281 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30282 tooltip : this.iconTooltip
30291 if(this.indicatorpos == 'right'){
30294 cls : 'roo-bootstrap-field-label ' + this.cls,
30303 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30304 tooltip : this.iconTooltip
30313 initEvents: function()
30315 Roo.bootstrap.Element.superclass.initEvents.call(this);
30317 this.indicator = this.indicatorEl();
30319 if(this.indicator){
30320 this.indicator.removeClass('visible');
30321 this.indicator.addClass('invisible');
30324 Roo.bootstrap.FieldLabel.register(this);
30327 indicatorEl : function()
30329 var indicator = this.el.select('i.roo-required-indicator',true).first();
30340 * Mark this field as valid
30342 markValid : function()
30344 if(this.indicator){
30345 this.indicator.removeClass('visible');
30346 this.indicator.addClass('invisible');
30349 this.el.removeClass(this.invalidClass);
30351 this.el.addClass(this.validClass);
30353 this.fireEvent('valid', this);
30357 * Mark this field as invalid
30358 * @param {String} msg The validation message
30360 markInvalid : function(msg)
30362 if(this.indicator){
30363 this.indicator.removeClass('invisible');
30364 this.indicator.addClass('visible');
30367 this.el.removeClass(this.validClass);
30369 this.el.addClass(this.invalidClass);
30371 this.fireEvent('invalid', this, msg);
30377 Roo.apply(Roo.bootstrap.FieldLabel, {
30382 * register a FieldLabel Group
30383 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30385 register : function(label)
30387 if(this.groups.hasOwnProperty(label.target)){
30391 this.groups[label.target] = label;
30395 * fetch a FieldLabel Group based on the target
30396 * @param {string} target
30397 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30399 get: function(target) {
30400 if (typeof(this.groups[target]) == 'undefined') {
30404 return this.groups[target] ;
30413 * page DateSplitField.
30419 * @class Roo.bootstrap.DateSplitField
30420 * @extends Roo.bootstrap.Component
30421 * Bootstrap DateSplitField class
30422 * @cfg {string} fieldLabel - the label associated
30423 * @cfg {Number} labelWidth set the width of label (0-12)
30424 * @cfg {String} labelAlign (top|left)
30425 * @cfg {Boolean} dayAllowBlank (true|false) default false
30426 * @cfg {Boolean} monthAllowBlank (true|false) default false
30427 * @cfg {Boolean} yearAllowBlank (true|false) default false
30428 * @cfg {string} dayPlaceholder
30429 * @cfg {string} monthPlaceholder
30430 * @cfg {string} yearPlaceholder
30431 * @cfg {string} dayFormat default 'd'
30432 * @cfg {string} monthFormat default 'm'
30433 * @cfg {string} yearFormat default 'Y'
30434 * @cfg {Number} labellg set the width of label (1-12)
30435 * @cfg {Number} labelmd set the width of label (1-12)
30436 * @cfg {Number} labelsm set the width of label (1-12)
30437 * @cfg {Number} labelxs set the width of label (1-12)
30441 * Create a new DateSplitField
30442 * @param {Object} config The config object
30445 Roo.bootstrap.DateSplitField = function(config){
30446 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30452 * getting the data of years
30453 * @param {Roo.bootstrap.DateSplitField} this
30454 * @param {Object} years
30459 * getting the data of days
30460 * @param {Roo.bootstrap.DateSplitField} this
30461 * @param {Object} days
30466 * Fires after the field has been marked as invalid.
30467 * @param {Roo.form.Field} this
30468 * @param {String} msg The validation message
30473 * Fires after the field has been validated with no errors.
30474 * @param {Roo.form.Field} this
30480 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30483 labelAlign : 'top',
30485 dayAllowBlank : false,
30486 monthAllowBlank : false,
30487 yearAllowBlank : false,
30488 dayPlaceholder : '',
30489 monthPlaceholder : '',
30490 yearPlaceholder : '',
30494 isFormField : true,
30500 getAutoCreate : function()
30504 cls : 'row roo-date-split-field-group',
30509 cls : 'form-hidden-field roo-date-split-field-group-value',
30515 var labelCls = 'col-md-12';
30516 var contentCls = 'col-md-4';
30518 if(this.fieldLabel){
30522 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30526 html : this.fieldLabel
30531 if(this.labelAlign == 'left'){
30533 if(this.labelWidth > 12){
30534 label.style = "width: " + this.labelWidth + 'px';
30537 if(this.labelWidth < 13 && this.labelmd == 0){
30538 this.labelmd = this.labelWidth;
30541 if(this.labellg > 0){
30542 labelCls = ' col-lg-' + this.labellg;
30543 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30546 if(this.labelmd > 0){
30547 labelCls = ' col-md-' + this.labelmd;
30548 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30551 if(this.labelsm > 0){
30552 labelCls = ' col-sm-' + this.labelsm;
30553 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30556 if(this.labelxs > 0){
30557 labelCls = ' col-xs-' + this.labelxs;
30558 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30562 label.cls += ' ' + labelCls;
30564 cfg.cn.push(label);
30567 Roo.each(['day', 'month', 'year'], function(t){
30570 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30577 inputEl: function ()
30579 return this.el.select('.roo-date-split-field-group-value', true).first();
30582 onRender : function(ct, position)
30586 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30588 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30590 this.dayField = new Roo.bootstrap.ComboBox({
30591 allowBlank : this.dayAllowBlank,
30592 alwaysQuery : true,
30593 displayField : 'value',
30596 forceSelection : true,
30598 placeholder : this.dayPlaceholder,
30599 selectOnFocus : true,
30600 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30601 triggerAction : 'all',
30603 valueField : 'value',
30604 store : new Roo.data.SimpleStore({
30605 data : (function() {
30607 _this.fireEvent('days', _this, days);
30610 fields : [ 'value' ]
30613 select : function (_self, record, index)
30615 _this.setValue(_this.getValue());
30620 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30622 this.monthField = new Roo.bootstrap.MonthField({
30623 after : '<i class=\"fa fa-calendar\"></i>',
30624 allowBlank : this.monthAllowBlank,
30625 placeholder : this.monthPlaceholder,
30628 render : function (_self)
30630 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30631 e.preventDefault();
30635 select : function (_self, oldvalue, newvalue)
30637 _this.setValue(_this.getValue());
30642 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30644 this.yearField = new Roo.bootstrap.ComboBox({
30645 allowBlank : this.yearAllowBlank,
30646 alwaysQuery : true,
30647 displayField : 'value',
30650 forceSelection : true,
30652 placeholder : this.yearPlaceholder,
30653 selectOnFocus : true,
30654 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30655 triggerAction : 'all',
30657 valueField : 'value',
30658 store : new Roo.data.SimpleStore({
30659 data : (function() {
30661 _this.fireEvent('years', _this, years);
30664 fields : [ 'value' ]
30667 select : function (_self, record, index)
30669 _this.setValue(_this.getValue());
30674 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30677 setValue : function(v, format)
30679 this.inputEl.dom.value = v;
30681 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30683 var d = Date.parseDate(v, f);
30690 this.setDay(d.format(this.dayFormat));
30691 this.setMonth(d.format(this.monthFormat));
30692 this.setYear(d.format(this.yearFormat));
30699 setDay : function(v)
30701 this.dayField.setValue(v);
30702 this.inputEl.dom.value = this.getValue();
30707 setMonth : function(v)
30709 this.monthField.setValue(v, true);
30710 this.inputEl.dom.value = this.getValue();
30715 setYear : function(v)
30717 this.yearField.setValue(v);
30718 this.inputEl.dom.value = this.getValue();
30723 getDay : function()
30725 return this.dayField.getValue();
30728 getMonth : function()
30730 return this.monthField.getValue();
30733 getYear : function()
30735 return this.yearField.getValue();
30738 getValue : function()
30740 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30742 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30752 this.inputEl.dom.value = '';
30757 validate : function()
30759 var d = this.dayField.validate();
30760 var m = this.monthField.validate();
30761 var y = this.yearField.validate();
30766 (!this.dayAllowBlank && !d) ||
30767 (!this.monthAllowBlank && !m) ||
30768 (!this.yearAllowBlank && !y)
30773 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30782 this.markInvalid();
30787 markValid : function()
30790 var label = this.el.select('label', true).first();
30791 var icon = this.el.select('i.fa-star', true).first();
30797 this.fireEvent('valid', this);
30801 * Mark this field as invalid
30802 * @param {String} msg The validation message
30804 markInvalid : function(msg)
30807 var label = this.el.select('label', true).first();
30808 var icon = this.el.select('i.fa-star', true).first();
30810 if(label && !icon){
30811 this.el.select('.roo-date-split-field-label', true).createChild({
30813 cls : 'text-danger fa fa-lg fa-star',
30814 tooltip : 'This field is required',
30815 style : 'margin-right:5px;'
30819 this.fireEvent('invalid', this, msg);
30822 clearInvalid : function()
30824 var label = this.el.select('label', true).first();
30825 var icon = this.el.select('i.fa-star', true).first();
30831 this.fireEvent('valid', this);
30834 getName: function()
30844 * http://masonry.desandro.com
30846 * The idea is to render all the bricks based on vertical width...
30848 * The original code extends 'outlayer' - we might need to use that....
30854 * @class Roo.bootstrap.LayoutMasonry
30855 * @extends Roo.bootstrap.Component
30856 * Bootstrap Layout Masonry class
30859 * Create a new Element
30860 * @param {Object} config The config object
30863 Roo.bootstrap.LayoutMasonry = function(config){
30865 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30869 Roo.bootstrap.LayoutMasonry.register(this);
30875 * Fire after layout the items
30876 * @param {Roo.bootstrap.LayoutMasonry} this
30877 * @param {Roo.EventObject} e
30884 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30887 * @cfg {Boolean} isLayoutInstant = no animation?
30889 isLayoutInstant : false, // needed?
30892 * @cfg {Number} boxWidth width of the columns
30897 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30902 * @cfg {Number} padWidth padding below box..
30907 * @cfg {Number} gutter gutter width..
30912 * @cfg {Number} maxCols maximum number of columns
30918 * @cfg {Boolean} isAutoInitial defalut true
30920 isAutoInitial : true,
30925 * @cfg {Boolean} isHorizontal defalut false
30927 isHorizontal : false,
30929 currentSize : null,
30935 bricks: null, //CompositeElement
30939 _isLayoutInited : false,
30941 // isAlternative : false, // only use for vertical layout...
30944 * @cfg {Number} alternativePadWidth padding below box..
30946 alternativePadWidth : 50,
30948 selectedBrick : [],
30950 getAutoCreate : function(){
30952 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30956 cls: 'blog-masonary-wrapper ' + this.cls,
30958 cls : 'mas-boxes masonary'
30965 getChildContainer: function( )
30967 if (this.boxesEl) {
30968 return this.boxesEl;
30971 this.boxesEl = this.el.select('.mas-boxes').first();
30973 return this.boxesEl;
30977 initEvents : function()
30981 if(this.isAutoInitial){
30982 Roo.log('hook children rendered');
30983 this.on('childrenrendered', function() {
30984 Roo.log('children rendered');
30990 initial : function()
30992 this.selectedBrick = [];
30994 this.currentSize = this.el.getBox(true);
30996 Roo.EventManager.onWindowResize(this.resize, this);
30998 if(!this.isAutoInitial){
31006 //this.layout.defer(500,this);
31010 resize : function()
31012 var cs = this.el.getBox(true);
31015 this.currentSize.width == cs.width &&
31016 this.currentSize.x == cs.x &&
31017 this.currentSize.height == cs.height &&
31018 this.currentSize.y == cs.y
31020 Roo.log("no change in with or X or Y");
31024 this.currentSize = cs;
31030 layout : function()
31032 this._resetLayout();
31034 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31036 this.layoutItems( isInstant );
31038 this._isLayoutInited = true;
31040 this.fireEvent('layout', this);
31044 _resetLayout : function()
31046 if(this.isHorizontal){
31047 this.horizontalMeasureColumns();
31051 this.verticalMeasureColumns();
31055 verticalMeasureColumns : function()
31057 this.getContainerWidth();
31059 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31060 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31064 var boxWidth = this.boxWidth + this.padWidth;
31066 if(this.containerWidth < this.boxWidth){
31067 boxWidth = this.containerWidth
31070 var containerWidth = this.containerWidth;
31072 var cols = Math.floor(containerWidth / boxWidth);
31074 this.cols = Math.max( cols, 1 );
31076 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31078 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31080 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31082 this.colWidth = boxWidth + avail - this.padWidth;
31084 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31085 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31088 horizontalMeasureColumns : function()
31090 this.getContainerWidth();
31092 var boxWidth = this.boxWidth;
31094 if(this.containerWidth < boxWidth){
31095 boxWidth = this.containerWidth;
31098 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31100 this.el.setHeight(boxWidth);
31104 getContainerWidth : function()
31106 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31109 layoutItems : function( isInstant )
31111 Roo.log(this.bricks);
31113 var items = Roo.apply([], this.bricks);
31115 if(this.isHorizontal){
31116 this._horizontalLayoutItems( items , isInstant );
31120 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31121 // this._verticalAlternativeLayoutItems( items , isInstant );
31125 this._verticalLayoutItems( items , isInstant );
31129 _verticalLayoutItems : function ( items , isInstant)
31131 if ( !items || !items.length ) {
31136 ['xs', 'xs', 'xs', 'tall'],
31137 ['xs', 'xs', 'tall'],
31138 ['xs', 'xs', 'sm'],
31139 ['xs', 'xs', 'xs'],
31145 ['sm', 'xs', 'xs'],
31149 ['tall', 'xs', 'xs', 'xs'],
31150 ['tall', 'xs', 'xs'],
31162 Roo.each(items, function(item, k){
31164 switch (item.size) {
31165 // these layouts take up a full box,
31176 boxes.push([item]);
31199 var filterPattern = function(box, length)
31207 var pattern = box.slice(0, length);
31211 Roo.each(pattern, function(i){
31212 format.push(i.size);
31215 Roo.each(standard, function(s){
31217 if(String(s) != String(format)){
31226 if(!match && length == 1){
31231 filterPattern(box, length - 1);
31235 queue.push(pattern);
31237 box = box.slice(length, box.length);
31239 filterPattern(box, 4);
31245 Roo.each(boxes, function(box, k){
31251 if(box.length == 1){
31256 filterPattern(box, 4);
31260 this._processVerticalLayoutQueue( queue, isInstant );
31264 // _verticalAlternativeLayoutItems : function( items , isInstant )
31266 // if ( !items || !items.length ) {
31270 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31274 _horizontalLayoutItems : function ( items , isInstant)
31276 if ( !items || !items.length || items.length < 3) {
31282 var eItems = items.slice(0, 3);
31284 items = items.slice(3, items.length);
31287 ['xs', 'xs', 'xs', 'wide'],
31288 ['xs', 'xs', 'wide'],
31289 ['xs', 'xs', 'sm'],
31290 ['xs', 'xs', 'xs'],
31296 ['sm', 'xs', 'xs'],
31300 ['wide', 'xs', 'xs', 'xs'],
31301 ['wide', 'xs', 'xs'],
31314 Roo.each(items, function(item, k){
31316 switch (item.size) {
31327 boxes.push([item]);
31351 var filterPattern = function(box, length)
31359 var pattern = box.slice(0, length);
31363 Roo.each(pattern, function(i){
31364 format.push(i.size);
31367 Roo.each(standard, function(s){
31369 if(String(s) != String(format)){
31378 if(!match && length == 1){
31383 filterPattern(box, length - 1);
31387 queue.push(pattern);
31389 box = box.slice(length, box.length);
31391 filterPattern(box, 4);
31397 Roo.each(boxes, function(box, k){
31403 if(box.length == 1){
31408 filterPattern(box, 4);
31415 var pos = this.el.getBox(true);
31419 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31421 var hit_end = false;
31423 Roo.each(queue, function(box){
31427 Roo.each(box, function(b){
31429 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31439 Roo.each(box, function(b){
31441 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31444 mx = Math.max(mx, b.x);
31448 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31452 Roo.each(box, function(b){
31454 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31468 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31471 /** Sets position of item in DOM
31472 * @param {Element} item
31473 * @param {Number} x - horizontal position
31474 * @param {Number} y - vertical position
31475 * @param {Boolean} isInstant - disables transitions
31477 _processVerticalLayoutQueue : function( queue, isInstant )
31479 var pos = this.el.getBox(true);
31484 for (var i = 0; i < this.cols; i++){
31488 Roo.each(queue, function(box, k){
31490 var col = k % this.cols;
31492 Roo.each(box, function(b,kk){
31494 b.el.position('absolute');
31496 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31497 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31499 if(b.size == 'md-left' || b.size == 'md-right'){
31500 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31501 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31504 b.el.setWidth(width);
31505 b.el.setHeight(height);
31507 b.el.select('iframe',true).setSize(width,height);
31511 for (var i = 0; i < this.cols; i++){
31513 if(maxY[i] < maxY[col]){
31518 col = Math.min(col, i);
31522 x = pos.x + col * (this.colWidth + this.padWidth);
31526 var positions = [];
31528 switch (box.length){
31530 positions = this.getVerticalOneBoxColPositions(x, y, box);
31533 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31536 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31539 positions = this.getVerticalFourBoxColPositions(x, y, box);
31545 Roo.each(box, function(b,kk){
31547 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31549 var sz = b.el.getSize();
31551 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31559 for (var i = 0; i < this.cols; i++){
31560 mY = Math.max(mY, maxY[i]);
31563 this.el.setHeight(mY - pos.y);
31567 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31569 // var pos = this.el.getBox(true);
31572 // var maxX = pos.right;
31574 // var maxHeight = 0;
31576 // Roo.each(items, function(item, k){
31580 // item.el.position('absolute');
31582 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31584 // item.el.setWidth(width);
31586 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31588 // item.el.setHeight(height);
31591 // item.el.setXY([x, y], isInstant ? false : true);
31593 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31596 // y = y + height + this.alternativePadWidth;
31598 // maxHeight = maxHeight + height + this.alternativePadWidth;
31602 // this.el.setHeight(maxHeight);
31606 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31608 var pos = this.el.getBox(true);
31613 var maxX = pos.right;
31615 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31617 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31619 Roo.each(queue, function(box, k){
31621 Roo.each(box, function(b, kk){
31623 b.el.position('absolute');
31625 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31626 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31628 if(b.size == 'md-left' || b.size == 'md-right'){
31629 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31630 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31633 b.el.setWidth(width);
31634 b.el.setHeight(height);
31642 var positions = [];
31644 switch (box.length){
31646 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31649 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31652 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31655 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31661 Roo.each(box, function(b,kk){
31663 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31665 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31673 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31675 Roo.each(eItems, function(b,k){
31677 b.size = (k == 0) ? 'sm' : 'xs';
31678 b.x = (k == 0) ? 2 : 1;
31679 b.y = (k == 0) ? 2 : 1;
31681 b.el.position('absolute');
31683 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31685 b.el.setWidth(width);
31687 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31689 b.el.setHeight(height);
31693 var positions = [];
31696 x : maxX - this.unitWidth * 2 - this.gutter,
31701 x : maxX - this.unitWidth,
31702 y : minY + (this.unitWidth + this.gutter) * 2
31706 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31710 Roo.each(eItems, function(b,k){
31712 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31718 getVerticalOneBoxColPositions : function(x, y, box)
31722 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31724 if(box[0].size == 'md-left'){
31728 if(box[0].size == 'md-right'){
31733 x : x + (this.unitWidth + this.gutter) * rand,
31740 getVerticalTwoBoxColPositions : function(x, y, box)
31744 if(box[0].size == 'xs'){
31748 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31752 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31766 x : x + (this.unitWidth + this.gutter) * 2,
31767 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31774 getVerticalThreeBoxColPositions : function(x, y, box)
31778 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31786 x : x + (this.unitWidth + this.gutter) * 1,
31791 x : x + (this.unitWidth + this.gutter) * 2,
31799 if(box[0].size == 'xs' && box[1].size == 'xs'){
31808 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31812 x : x + (this.unitWidth + this.gutter) * 1,
31826 x : x + (this.unitWidth + this.gutter) * 2,
31831 x : x + (this.unitWidth + this.gutter) * 2,
31832 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31839 getVerticalFourBoxColPositions : function(x, y, box)
31843 if(box[0].size == 'xs'){
31852 y : y + (this.unitHeight + this.gutter) * 1
31857 y : y + (this.unitHeight + this.gutter) * 2
31861 x : x + (this.unitWidth + this.gutter) * 1,
31875 x : x + (this.unitWidth + this.gutter) * 2,
31880 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31881 y : y + (this.unitHeight + this.gutter) * 1
31885 x : x + (this.unitWidth + this.gutter) * 2,
31886 y : y + (this.unitWidth + this.gutter) * 2
31893 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31897 if(box[0].size == 'md-left'){
31899 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31906 if(box[0].size == 'md-right'){
31908 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31909 y : minY + (this.unitWidth + this.gutter) * 1
31915 var rand = Math.floor(Math.random() * (4 - box[0].y));
31918 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31919 y : minY + (this.unitWidth + this.gutter) * rand
31926 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31930 if(box[0].size == 'xs'){
31933 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31938 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31939 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31947 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31952 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31953 y : minY + (this.unitWidth + this.gutter) * 2
31960 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31964 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31967 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31972 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31973 y : minY + (this.unitWidth + this.gutter) * 1
31977 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31978 y : minY + (this.unitWidth + this.gutter) * 2
31985 if(box[0].size == 'xs' && box[1].size == 'xs'){
31988 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31993 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31998 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31999 y : minY + (this.unitWidth + this.gutter) * 1
32007 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32012 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32013 y : minY + (this.unitWidth + this.gutter) * 2
32017 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32018 y : minY + (this.unitWidth + this.gutter) * 2
32025 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32029 if(box[0].size == 'xs'){
32032 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32037 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32042 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),
32047 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32048 y : minY + (this.unitWidth + this.gutter) * 1
32056 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32061 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32062 y : minY + (this.unitWidth + this.gutter) * 2
32066 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32067 y : minY + (this.unitWidth + this.gutter) * 2
32071 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),
32072 y : minY + (this.unitWidth + this.gutter) * 2
32080 * remove a Masonry Brick
32081 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32083 removeBrick : function(brick_id)
32089 for (var i = 0; i<this.bricks.length; i++) {
32090 if (this.bricks[i].id == brick_id) {
32091 this.bricks.splice(i,1);
32092 this.el.dom.removeChild(Roo.get(brick_id).dom);
32099 * adds a Masonry Brick
32100 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32102 addBrick : function(cfg)
32104 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32105 //this.register(cn);
32106 cn.parentId = this.id;
32107 cn.render(this.el);
32112 * register a Masonry Brick
32113 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32116 register : function(brick)
32118 this.bricks.push(brick);
32119 brick.masonryId = this.id;
32123 * clear all the Masonry Brick
32125 clearAll : function()
32128 //this.getChildContainer().dom.innerHTML = "";
32129 this.el.dom.innerHTML = '';
32132 getSelected : function()
32134 if (!this.selectedBrick) {
32138 return this.selectedBrick;
32142 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32146 * register a Masonry Layout
32147 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32150 register : function(layout)
32152 this.groups[layout.id] = layout;
32155 * fetch a Masonry Layout based on the masonry layout ID
32156 * @param {string} the masonry layout to add
32157 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32160 get: function(layout_id) {
32161 if (typeof(this.groups[layout_id]) == 'undefined') {
32164 return this.groups[layout_id] ;
32176 * http://masonry.desandro.com
32178 * The idea is to render all the bricks based on vertical width...
32180 * The original code extends 'outlayer' - we might need to use that....
32186 * @class Roo.bootstrap.LayoutMasonryAuto
32187 * @extends Roo.bootstrap.Component
32188 * Bootstrap Layout Masonry class
32191 * Create a new Element
32192 * @param {Object} config The config object
32195 Roo.bootstrap.LayoutMasonryAuto = function(config){
32196 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32199 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32202 * @cfg {Boolean} isFitWidth - resize the width..
32204 isFitWidth : false, // options..
32206 * @cfg {Boolean} isOriginLeft = left align?
32208 isOriginLeft : true,
32210 * @cfg {Boolean} isOriginTop = top align?
32212 isOriginTop : false,
32214 * @cfg {Boolean} isLayoutInstant = no animation?
32216 isLayoutInstant : false, // needed?
32218 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32220 isResizingContainer : true,
32222 * @cfg {Number} columnWidth width of the columns
32228 * @cfg {Number} maxCols maximum number of columns
32233 * @cfg {Number} padHeight padding below box..
32239 * @cfg {Boolean} isAutoInitial defalut true
32242 isAutoInitial : true,
32248 initialColumnWidth : 0,
32249 currentSize : null,
32251 colYs : null, // array.
32258 bricks: null, //CompositeElement
32259 cols : 0, // array?
32260 // element : null, // wrapped now this.el
32261 _isLayoutInited : null,
32264 getAutoCreate : function(){
32268 cls: 'blog-masonary-wrapper ' + this.cls,
32270 cls : 'mas-boxes masonary'
32277 getChildContainer: function( )
32279 if (this.boxesEl) {
32280 return this.boxesEl;
32283 this.boxesEl = this.el.select('.mas-boxes').first();
32285 return this.boxesEl;
32289 initEvents : function()
32293 if(this.isAutoInitial){
32294 Roo.log('hook children rendered');
32295 this.on('childrenrendered', function() {
32296 Roo.log('children rendered');
32303 initial : function()
32305 this.reloadItems();
32307 this.currentSize = this.el.getBox(true);
32309 /// was window resize... - let's see if this works..
32310 Roo.EventManager.onWindowResize(this.resize, this);
32312 if(!this.isAutoInitial){
32317 this.layout.defer(500,this);
32320 reloadItems: function()
32322 this.bricks = this.el.select('.masonry-brick', true);
32324 this.bricks.each(function(b) {
32325 //Roo.log(b.getSize());
32326 if (!b.attr('originalwidth')) {
32327 b.attr('originalwidth', b.getSize().width);
32332 Roo.log(this.bricks.elements.length);
32335 resize : function()
32338 var cs = this.el.getBox(true);
32340 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32341 Roo.log("no change in with or X");
32344 this.currentSize = cs;
32348 layout : function()
32351 this._resetLayout();
32352 //this._manageStamps();
32354 // don't animate first layout
32355 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32356 this.layoutItems( isInstant );
32358 // flag for initalized
32359 this._isLayoutInited = true;
32362 layoutItems : function( isInstant )
32364 //var items = this._getItemsForLayout( this.items );
32365 // original code supports filtering layout items.. we just ignore it..
32367 this._layoutItems( this.bricks , isInstant );
32369 this._postLayout();
32371 _layoutItems : function ( items , isInstant)
32373 //this.fireEvent( 'layout', this, items );
32376 if ( !items || !items.elements.length ) {
32377 // no items, emit event with empty array
32382 items.each(function(item) {
32383 Roo.log("layout item");
32385 // get x/y object from method
32386 var position = this._getItemLayoutPosition( item );
32388 position.item = item;
32389 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32390 queue.push( position );
32393 this._processLayoutQueue( queue );
32395 /** Sets position of item in DOM
32396 * @param {Element} item
32397 * @param {Number} x - horizontal position
32398 * @param {Number} y - vertical position
32399 * @param {Boolean} isInstant - disables transitions
32401 _processLayoutQueue : function( queue )
32403 for ( var i=0, len = queue.length; i < len; i++ ) {
32404 var obj = queue[i];
32405 obj.item.position('absolute');
32406 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32412 * Any logic you want to do after each layout,
32413 * i.e. size the container
32415 _postLayout : function()
32417 this.resizeContainer();
32420 resizeContainer : function()
32422 if ( !this.isResizingContainer ) {
32425 var size = this._getContainerSize();
32427 this.el.setSize(size.width,size.height);
32428 this.boxesEl.setSize(size.width,size.height);
32434 _resetLayout : function()
32436 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32437 this.colWidth = this.el.getWidth();
32438 //this.gutter = this.el.getWidth();
32440 this.measureColumns();
32446 this.colYs.push( 0 );
32452 measureColumns : function()
32454 this.getContainerWidth();
32455 // if columnWidth is 0, default to outerWidth of first item
32456 if ( !this.columnWidth ) {
32457 var firstItem = this.bricks.first();
32458 Roo.log(firstItem);
32459 this.columnWidth = this.containerWidth;
32460 if (firstItem && firstItem.attr('originalwidth') ) {
32461 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32463 // columnWidth fall back to item of first element
32464 Roo.log("set column width?");
32465 this.initialColumnWidth = this.columnWidth ;
32467 // if first elem has no width, default to size of container
32472 if (this.initialColumnWidth) {
32473 this.columnWidth = this.initialColumnWidth;
32478 // column width is fixed at the top - however if container width get's smaller we should
32481 // this bit calcs how man columns..
32483 var columnWidth = this.columnWidth += this.gutter;
32485 // calculate columns
32486 var containerWidth = this.containerWidth + this.gutter;
32488 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32489 // fix rounding errors, typically with gutters
32490 var excess = columnWidth - containerWidth % columnWidth;
32493 // if overshoot is less than a pixel, round up, otherwise floor it
32494 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32495 cols = Math[ mathMethod ]( cols );
32496 this.cols = Math.max( cols, 1 );
32497 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32499 // padding positioning..
32500 var totalColWidth = this.cols * this.columnWidth;
32501 var padavail = this.containerWidth - totalColWidth;
32502 // so for 2 columns - we need 3 'pads'
32504 var padNeeded = (1+this.cols) * this.padWidth;
32506 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32508 this.columnWidth += padExtra
32509 //this.padWidth = Math.floor(padavail / ( this.cols));
32511 // adjust colum width so that padding is fixed??
32513 // we have 3 columns ... total = width * 3
32514 // we have X left over... that should be used by
32516 //if (this.expandC) {
32524 getContainerWidth : function()
32526 /* // container is parent if fit width
32527 var container = this.isFitWidth ? this.element.parentNode : this.element;
32528 // check that this.size and size are there
32529 // IE8 triggers resize on body size change, so they might not be
32531 var size = getSize( container ); //FIXME
32532 this.containerWidth = size && size.innerWidth; //FIXME
32535 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32539 _getItemLayoutPosition : function( item ) // what is item?
32541 // we resize the item to our columnWidth..
32543 item.setWidth(this.columnWidth);
32544 item.autoBoxAdjust = false;
32546 var sz = item.getSize();
32548 // how many columns does this brick span
32549 var remainder = this.containerWidth % this.columnWidth;
32551 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32552 // round if off by 1 pixel, otherwise use ceil
32553 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32554 colSpan = Math.min( colSpan, this.cols );
32556 // normally this should be '1' as we dont' currently allow multi width columns..
32558 var colGroup = this._getColGroup( colSpan );
32559 // get the minimum Y value from the columns
32560 var minimumY = Math.min.apply( Math, colGroup );
32561 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32563 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32565 // position the brick
32567 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32568 y: this.currentSize.y + minimumY + this.padHeight
32572 // apply setHeight to necessary columns
32573 var setHeight = minimumY + sz.height + this.padHeight;
32574 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32576 var setSpan = this.cols + 1 - colGroup.length;
32577 for ( var i = 0; i < setSpan; i++ ) {
32578 this.colYs[ shortColIndex + i ] = setHeight ;
32585 * @param {Number} colSpan - number of columns the element spans
32586 * @returns {Array} colGroup
32588 _getColGroup : function( colSpan )
32590 if ( colSpan < 2 ) {
32591 // if brick spans only one column, use all the column Ys
32596 // how many different places could this brick fit horizontally
32597 var groupCount = this.cols + 1 - colSpan;
32598 // for each group potential horizontal position
32599 for ( var i = 0; i < groupCount; i++ ) {
32600 // make an array of colY values for that one group
32601 var groupColYs = this.colYs.slice( i, i + colSpan );
32602 // and get the max value of the array
32603 colGroup[i] = Math.max.apply( Math, groupColYs );
32608 _manageStamp : function( stamp )
32610 var stampSize = stamp.getSize();
32611 var offset = stamp.getBox();
32612 // get the columns that this stamp affects
32613 var firstX = this.isOriginLeft ? offset.x : offset.right;
32614 var lastX = firstX + stampSize.width;
32615 var firstCol = Math.floor( firstX / this.columnWidth );
32616 firstCol = Math.max( 0, firstCol );
32618 var lastCol = Math.floor( lastX / this.columnWidth );
32619 // lastCol should not go over if multiple of columnWidth #425
32620 lastCol -= lastX % this.columnWidth ? 0 : 1;
32621 lastCol = Math.min( this.cols - 1, lastCol );
32623 // set colYs to bottom of the stamp
32624 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32627 for ( var i = firstCol; i <= lastCol; i++ ) {
32628 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32633 _getContainerSize : function()
32635 this.maxY = Math.max.apply( Math, this.colYs );
32640 if ( this.isFitWidth ) {
32641 size.width = this._getContainerFitWidth();
32647 _getContainerFitWidth : function()
32649 var unusedCols = 0;
32650 // count unused columns
32653 if ( this.colYs[i] !== 0 ) {
32658 // fit container to columns that have been used
32659 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32662 needsResizeLayout : function()
32664 var previousWidth = this.containerWidth;
32665 this.getContainerWidth();
32666 return previousWidth !== this.containerWidth;
32681 * @class Roo.bootstrap.MasonryBrick
32682 * @extends Roo.bootstrap.Component
32683 * Bootstrap MasonryBrick class
32686 * Create a new MasonryBrick
32687 * @param {Object} config The config object
32690 Roo.bootstrap.MasonryBrick = function(config){
32692 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32694 Roo.bootstrap.MasonryBrick.register(this);
32700 * When a MasonryBrick is clcik
32701 * @param {Roo.bootstrap.MasonryBrick} this
32702 * @param {Roo.EventObject} e
32708 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32711 * @cfg {String} title
32715 * @cfg {String} html
32719 * @cfg {String} bgimage
32723 * @cfg {String} videourl
32727 * @cfg {String} cls
32731 * @cfg {String} href
32735 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32740 * @cfg {String} placetitle (center|bottom)
32745 * @cfg {Boolean} isFitContainer defalut true
32747 isFitContainer : true,
32750 * @cfg {Boolean} preventDefault defalut false
32752 preventDefault : false,
32755 * @cfg {Boolean} inverse defalut false
32757 maskInverse : false,
32759 getAutoCreate : function()
32761 if(!this.isFitContainer){
32762 return this.getSplitAutoCreate();
32765 var cls = 'masonry-brick masonry-brick-full';
32767 if(this.href.length){
32768 cls += ' masonry-brick-link';
32771 if(this.bgimage.length){
32772 cls += ' masonry-brick-image';
32775 if(this.maskInverse){
32776 cls += ' mask-inverse';
32779 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32780 cls += ' enable-mask';
32784 cls += ' masonry-' + this.size + '-brick';
32787 if(this.placetitle.length){
32789 switch (this.placetitle) {
32791 cls += ' masonry-center-title';
32794 cls += ' masonry-bottom-title';
32801 if(!this.html.length && !this.bgimage.length){
32802 cls += ' masonry-center-title';
32805 if(!this.html.length && this.bgimage.length){
32806 cls += ' masonry-bottom-title';
32811 cls += ' ' + this.cls;
32815 tag: (this.href.length) ? 'a' : 'div',
32820 cls: 'masonry-brick-mask'
32824 cls: 'masonry-brick-paragraph',
32830 if(this.href.length){
32831 cfg.href = this.href;
32834 var cn = cfg.cn[1].cn;
32836 if(this.title.length){
32839 cls: 'masonry-brick-title',
32844 if(this.html.length){
32847 cls: 'masonry-brick-text',
32852 if (!this.title.length && !this.html.length) {
32853 cfg.cn[1].cls += ' hide';
32856 if(this.bgimage.length){
32859 cls: 'masonry-brick-image-view',
32864 if(this.videourl.length){
32865 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32866 // youtube support only?
32869 cls: 'masonry-brick-image-view',
32872 allowfullscreen : true
32880 getSplitAutoCreate : function()
32882 var cls = 'masonry-brick masonry-brick-split';
32884 if(this.href.length){
32885 cls += ' masonry-brick-link';
32888 if(this.bgimage.length){
32889 cls += ' masonry-brick-image';
32893 cls += ' masonry-' + this.size + '-brick';
32896 switch (this.placetitle) {
32898 cls += ' masonry-center-title';
32901 cls += ' masonry-bottom-title';
32904 if(!this.bgimage.length){
32905 cls += ' masonry-center-title';
32908 if(this.bgimage.length){
32909 cls += ' masonry-bottom-title';
32915 cls += ' ' + this.cls;
32919 tag: (this.href.length) ? 'a' : 'div',
32924 cls: 'masonry-brick-split-head',
32928 cls: 'masonry-brick-paragraph',
32935 cls: 'masonry-brick-split-body',
32941 if(this.href.length){
32942 cfg.href = this.href;
32945 if(this.title.length){
32946 cfg.cn[0].cn[0].cn.push({
32948 cls: 'masonry-brick-title',
32953 if(this.html.length){
32954 cfg.cn[1].cn.push({
32956 cls: 'masonry-brick-text',
32961 if(this.bgimage.length){
32962 cfg.cn[0].cn.push({
32964 cls: 'masonry-brick-image-view',
32969 if(this.videourl.length){
32970 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32971 // youtube support only?
32972 cfg.cn[0].cn.cn.push({
32974 cls: 'masonry-brick-image-view',
32977 allowfullscreen : true
32984 initEvents: function()
32986 switch (this.size) {
33019 this.el.on('touchstart', this.onTouchStart, this);
33020 this.el.on('touchmove', this.onTouchMove, this);
33021 this.el.on('touchend', this.onTouchEnd, this);
33022 this.el.on('contextmenu', this.onContextMenu, this);
33024 this.el.on('mouseenter' ,this.enter, this);
33025 this.el.on('mouseleave', this.leave, this);
33026 this.el.on('click', this.onClick, this);
33029 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33030 this.parent().bricks.push(this);
33035 onClick: function(e, el)
33037 var time = this.endTimer - this.startTimer;
33038 // Roo.log(e.preventDefault());
33041 e.preventDefault();
33046 if(!this.preventDefault){
33050 e.preventDefault();
33052 if (this.activeClass != '') {
33053 this.selectBrick();
33056 this.fireEvent('click', this, e);
33059 enter: function(e, el)
33061 e.preventDefault();
33063 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33067 if(this.bgimage.length && this.html.length){
33068 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33072 leave: function(e, el)
33074 e.preventDefault();
33076 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33080 if(this.bgimage.length && this.html.length){
33081 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33085 onTouchStart: function(e, el)
33087 // e.preventDefault();
33089 this.touchmoved = false;
33091 if(!this.isFitContainer){
33095 if(!this.bgimage.length || !this.html.length){
33099 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33101 this.timer = new Date().getTime();
33105 onTouchMove: function(e, el)
33107 this.touchmoved = true;
33110 onContextMenu : function(e,el)
33112 e.preventDefault();
33113 e.stopPropagation();
33117 onTouchEnd: function(e, el)
33119 // e.preventDefault();
33121 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33128 if(!this.bgimage.length || !this.html.length){
33130 if(this.href.length){
33131 window.location.href = this.href;
33137 if(!this.isFitContainer){
33141 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33143 window.location.href = this.href;
33146 //selection on single brick only
33147 selectBrick : function() {
33149 if (!this.parentId) {
33153 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33154 var index = m.selectedBrick.indexOf(this.id);
33157 m.selectedBrick.splice(index,1);
33158 this.el.removeClass(this.activeClass);
33162 for(var i = 0; i < m.selectedBrick.length; i++) {
33163 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33164 b.el.removeClass(b.activeClass);
33167 m.selectedBrick = [];
33169 m.selectedBrick.push(this.id);
33170 this.el.addClass(this.activeClass);
33174 isSelected : function(){
33175 return this.el.hasClass(this.activeClass);
33180 Roo.apply(Roo.bootstrap.MasonryBrick, {
33183 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33185 * register a Masonry Brick
33186 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33189 register : function(brick)
33191 //this.groups[brick.id] = brick;
33192 this.groups.add(brick.id, brick);
33195 * fetch a masonry brick based on the masonry brick ID
33196 * @param {string} the masonry brick to add
33197 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33200 get: function(brick_id)
33202 // if (typeof(this.groups[brick_id]) == 'undefined') {
33205 // return this.groups[brick_id] ;
33207 if(this.groups.key(brick_id)) {
33208 return this.groups.key(brick_id);
33226 * @class Roo.bootstrap.Brick
33227 * @extends Roo.bootstrap.Component
33228 * Bootstrap Brick class
33231 * Create a new Brick
33232 * @param {Object} config The config object
33235 Roo.bootstrap.Brick = function(config){
33236 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33242 * When a Brick is click
33243 * @param {Roo.bootstrap.Brick} this
33244 * @param {Roo.EventObject} e
33250 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33253 * @cfg {String} title
33257 * @cfg {String} html
33261 * @cfg {String} bgimage
33265 * @cfg {String} cls
33269 * @cfg {String} href
33273 * @cfg {String} video
33277 * @cfg {Boolean} square
33281 getAutoCreate : function()
33283 var cls = 'roo-brick';
33285 if(this.href.length){
33286 cls += ' roo-brick-link';
33289 if(this.bgimage.length){
33290 cls += ' roo-brick-image';
33293 if(!this.html.length && !this.bgimage.length){
33294 cls += ' roo-brick-center-title';
33297 if(!this.html.length && this.bgimage.length){
33298 cls += ' roo-brick-bottom-title';
33302 cls += ' ' + this.cls;
33306 tag: (this.href.length) ? 'a' : 'div',
33311 cls: 'roo-brick-paragraph',
33317 if(this.href.length){
33318 cfg.href = this.href;
33321 var cn = cfg.cn[0].cn;
33323 if(this.title.length){
33326 cls: 'roo-brick-title',
33331 if(this.html.length){
33334 cls: 'roo-brick-text',
33341 if(this.bgimage.length){
33344 cls: 'roo-brick-image-view',
33352 initEvents: function()
33354 if(this.title.length || this.html.length){
33355 this.el.on('mouseenter' ,this.enter, this);
33356 this.el.on('mouseleave', this.leave, this);
33359 Roo.EventManager.onWindowResize(this.resize, this);
33361 if(this.bgimage.length){
33362 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33363 this.imageEl.on('load', this.onImageLoad, this);
33370 onImageLoad : function()
33375 resize : function()
33377 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33379 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33381 if(this.bgimage.length){
33382 var image = this.el.select('.roo-brick-image-view', true).first();
33384 image.setWidth(paragraph.getWidth());
33387 image.setHeight(paragraph.getWidth());
33390 this.el.setHeight(image.getHeight());
33391 paragraph.setHeight(image.getHeight());
33397 enter: function(e, el)
33399 e.preventDefault();
33401 if(this.bgimage.length){
33402 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33403 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33407 leave: function(e, el)
33409 e.preventDefault();
33411 if(this.bgimage.length){
33412 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33413 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33428 * @class Roo.bootstrap.NumberField
33429 * @extends Roo.bootstrap.Input
33430 * Bootstrap NumberField class
33436 * Create a new NumberField
33437 * @param {Object} config The config object
33440 Roo.bootstrap.NumberField = function(config){
33441 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33444 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33447 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33449 allowDecimals : true,
33451 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33453 decimalSeparator : ".",
33455 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33457 decimalPrecision : 2,
33459 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33461 allowNegative : true,
33464 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33468 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33470 minValue : Number.NEGATIVE_INFINITY,
33472 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33474 maxValue : Number.MAX_VALUE,
33476 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33478 minText : "The minimum value for this field is {0}",
33480 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33482 maxText : "The maximum value for this field is {0}",
33484 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33485 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33487 nanText : "{0} is not a valid number",
33489 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33491 thousandsDelimiter : false,
33493 * @cfg {String} valueAlign alignment of value
33495 valueAlign : "left",
33497 getAutoCreate : function()
33499 var hiddenInput = {
33503 cls: 'hidden-number-input'
33507 hiddenInput.name = this.name;
33512 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33514 this.name = hiddenInput.name;
33516 if(cfg.cn.length > 0) {
33517 cfg.cn.push(hiddenInput);
33524 initEvents : function()
33526 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33528 var allowed = "0123456789";
33530 if(this.allowDecimals){
33531 allowed += this.decimalSeparator;
33534 if(this.allowNegative){
33538 if(this.thousandsDelimiter) {
33542 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33544 var keyPress = function(e){
33546 var k = e.getKey();
33548 var c = e.getCharCode();
33551 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33552 allowed.indexOf(String.fromCharCode(c)) === -1
33558 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33562 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33567 this.el.on("keypress", keyPress, this);
33570 validateValue : function(value)
33573 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33577 var num = this.parseValue(value);
33580 this.markInvalid(String.format(this.nanText, value));
33584 if(num < this.minValue){
33585 this.markInvalid(String.format(this.minText, this.minValue));
33589 if(num > this.maxValue){
33590 this.markInvalid(String.format(this.maxText, this.maxValue));
33597 getValue : function()
33599 var v = this.hiddenEl().getValue();
33601 return this.fixPrecision(this.parseValue(v));
33604 parseValue : function(value)
33606 if(this.thousandsDelimiter) {
33608 r = new RegExp(",", "g");
33609 value = value.replace(r, "");
33612 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33613 return isNaN(value) ? '' : value;
33616 fixPrecision : function(value)
33618 if(this.thousandsDelimiter) {
33620 r = new RegExp(",", "g");
33621 value = value.replace(r, "");
33624 var nan = isNaN(value);
33626 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33627 return nan ? '' : value;
33629 return parseFloat(value).toFixed(this.decimalPrecision);
33632 setValue : function(v)
33634 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33640 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33642 this.inputEl().dom.value = (v == '') ? '' :
33643 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33645 if(!this.allowZero && v === '0') {
33646 this.hiddenEl().dom.value = '';
33647 this.inputEl().dom.value = '';
33654 decimalPrecisionFcn : function(v)
33656 return Math.floor(v);
33659 beforeBlur : function()
33661 var v = this.parseValue(this.getRawValue());
33663 if(v || v === 0 || v === ''){
33668 hiddenEl : function()
33670 return this.el.select('input.hidden-number-input',true).first();
33682 * @class Roo.bootstrap.DocumentSlider
33683 * @extends Roo.bootstrap.Component
33684 * Bootstrap DocumentSlider class
33687 * Create a new DocumentViewer
33688 * @param {Object} config The config object
33691 Roo.bootstrap.DocumentSlider = function(config){
33692 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33699 * Fire after initEvent
33700 * @param {Roo.bootstrap.DocumentSlider} this
33705 * Fire after update
33706 * @param {Roo.bootstrap.DocumentSlider} this
33712 * @param {Roo.bootstrap.DocumentSlider} this
33718 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33724 getAutoCreate : function()
33728 cls : 'roo-document-slider',
33732 cls : 'roo-document-slider-header',
33736 cls : 'roo-document-slider-header-title'
33742 cls : 'roo-document-slider-body',
33746 cls : 'roo-document-slider-prev',
33750 cls : 'fa fa-chevron-left'
33756 cls : 'roo-document-slider-thumb',
33760 cls : 'roo-document-slider-image'
33766 cls : 'roo-document-slider-next',
33770 cls : 'fa fa-chevron-right'
33782 initEvents : function()
33784 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33785 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33787 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33788 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33790 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33791 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33793 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33794 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33796 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33797 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33799 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33800 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33802 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33803 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33805 this.thumbEl.on('click', this.onClick, this);
33807 this.prevIndicator.on('click', this.prev, this);
33809 this.nextIndicator.on('click', this.next, this);
33813 initial : function()
33815 if(this.files.length){
33816 this.indicator = 1;
33820 this.fireEvent('initial', this);
33823 update : function()
33825 this.imageEl.attr('src', this.files[this.indicator - 1]);
33827 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33829 this.prevIndicator.show();
33831 if(this.indicator == 1){
33832 this.prevIndicator.hide();
33835 this.nextIndicator.show();
33837 if(this.indicator == this.files.length){
33838 this.nextIndicator.hide();
33841 this.thumbEl.scrollTo('top');
33843 this.fireEvent('update', this);
33846 onClick : function(e)
33848 e.preventDefault();
33850 this.fireEvent('click', this);
33855 e.preventDefault();
33857 this.indicator = Math.max(1, this.indicator - 1);
33864 e.preventDefault();
33866 this.indicator = Math.min(this.files.length, this.indicator + 1);
33880 * @class Roo.bootstrap.RadioSet
33881 * @extends Roo.bootstrap.Input
33882 * Bootstrap RadioSet class
33883 * @cfg {String} indicatorpos (left|right) default left
33884 * @cfg {Boolean} inline (true|false) inline the element (default true)
33885 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33887 * Create a new RadioSet
33888 * @param {Object} config The config object
33891 Roo.bootstrap.RadioSet = function(config){
33893 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33897 Roo.bootstrap.RadioSet.register(this);
33902 * Fires when the element is checked or unchecked.
33903 * @param {Roo.bootstrap.RadioSet} this This radio
33904 * @param {Roo.bootstrap.Radio} item The checked item
33909 * Fires when the element is click.
33910 * @param {Roo.bootstrap.RadioSet} this This radio set
33911 * @param {Roo.bootstrap.Radio} item The checked item
33912 * @param {Roo.EventObject} e The event object
33919 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33927 indicatorpos : 'left',
33929 getAutoCreate : function()
33933 cls : 'roo-radio-set-label',
33937 html : this.fieldLabel
33942 if(this.indicatorpos == 'left'){
33945 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33946 tooltip : 'This field is required'
33951 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33952 tooltip : 'This field is required'
33958 cls : 'roo-radio-set-items'
33961 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33963 if (align === 'left' && this.fieldLabel.length) {
33966 cls : "roo-radio-set-right",
33972 if(this.labelWidth > 12){
33973 label.style = "width: " + this.labelWidth + 'px';
33976 if(this.labelWidth < 13 && this.labelmd == 0){
33977 this.labelmd = this.labelWidth;
33980 if(this.labellg > 0){
33981 label.cls += ' col-lg-' + this.labellg;
33982 items.cls += ' col-lg-' + (12 - this.labellg);
33985 if(this.labelmd > 0){
33986 label.cls += ' col-md-' + this.labelmd;
33987 items.cls += ' col-md-' + (12 - this.labelmd);
33990 if(this.labelsm > 0){
33991 label.cls += ' col-sm-' + this.labelsm;
33992 items.cls += ' col-sm-' + (12 - this.labelsm);
33995 if(this.labelxs > 0){
33996 label.cls += ' col-xs-' + this.labelxs;
33997 items.cls += ' col-xs-' + (12 - this.labelxs);
34003 cls : 'roo-radio-set',
34007 cls : 'roo-radio-set-input',
34010 value : this.value ? this.value : ''
34017 if(this.weight.length){
34018 cfg.cls += ' roo-radio-' + this.weight;
34022 cfg.cls += ' roo-radio-set-inline';
34026 ['xs','sm','md','lg'].map(function(size){
34027 if (settings[size]) {
34028 cfg.cls += ' col-' + size + '-' + settings[size];
34036 initEvents : function()
34038 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34039 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34041 if(!this.fieldLabel.length){
34042 this.labelEl.hide();
34045 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34046 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34048 this.indicator = this.indicatorEl();
34050 if(this.indicator){
34051 this.indicator.addClass('invisible');
34054 this.originalValue = this.getValue();
34058 inputEl: function ()
34060 return this.el.select('.roo-radio-set-input', true).first();
34063 getChildContainer : function()
34065 return this.itemsEl;
34068 register : function(item)
34070 this.radioes.push(item);
34074 validate : function()
34076 if(this.getVisibilityEl().hasClass('hidden')){
34082 Roo.each(this.radioes, function(i){
34091 if(this.allowBlank) {
34095 if(this.disabled || valid){
34100 this.markInvalid();
34105 markValid : function()
34107 if(this.labelEl.isVisible(true)){
34108 this.indicatorEl().removeClass('visible');
34109 this.indicatorEl().addClass('invisible');
34112 this.el.removeClass([this.invalidClass, this.validClass]);
34113 this.el.addClass(this.validClass);
34115 this.fireEvent('valid', this);
34118 markInvalid : function(msg)
34120 if(this.allowBlank || this.disabled){
34124 if(this.labelEl.isVisible(true)){
34125 this.indicatorEl().removeClass('invisible');
34126 this.indicatorEl().addClass('visible');
34129 this.el.removeClass([this.invalidClass, this.validClass]);
34130 this.el.addClass(this.invalidClass);
34132 this.fireEvent('invalid', this, msg);
34136 setValue : function(v, suppressEvent)
34138 if(this.value === v){
34145 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34148 Roo.each(this.radioes, function(i){
34150 i.el.removeClass('checked');
34153 Roo.each(this.radioes, function(i){
34155 if(i.value === v || i.value.toString() === v.toString()){
34157 i.el.addClass('checked');
34159 if(suppressEvent !== true){
34160 this.fireEvent('check', this, i);
34171 clearInvalid : function(){
34173 if(!this.el || this.preventMark){
34177 this.el.removeClass([this.invalidClass]);
34179 this.fireEvent('valid', this);
34184 Roo.apply(Roo.bootstrap.RadioSet, {
34188 register : function(set)
34190 this.groups[set.name] = set;
34193 get: function(name)
34195 if (typeof(this.groups[name]) == 'undefined') {
34199 return this.groups[name] ;
34205 * Ext JS Library 1.1.1
34206 * Copyright(c) 2006-2007, Ext JS, LLC.
34208 * Originally Released Under LGPL - original licence link has changed is not relivant.
34211 * <script type="text/javascript">
34216 * @class Roo.bootstrap.SplitBar
34217 * @extends Roo.util.Observable
34218 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34222 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34223 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34224 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34225 split.minSize = 100;
34226 split.maxSize = 600;
34227 split.animate = true;
34228 split.on('moved', splitterMoved);
34231 * Create a new SplitBar
34232 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34233 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34234 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34235 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34236 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34237 position of the SplitBar).
34239 Roo.bootstrap.SplitBar = function(cfg){
34244 // dragElement : elm
34245 // resizingElement: el,
34247 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34248 // placement : Roo.bootstrap.SplitBar.LEFT ,
34249 // existingProxy ???
34252 this.el = Roo.get(cfg.dragElement, true);
34253 this.el.dom.unselectable = "on";
34255 this.resizingEl = Roo.get(cfg.resizingElement, true);
34259 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34260 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34263 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34266 * The minimum size of the resizing element. (Defaults to 0)
34272 * The maximum size of the resizing element. (Defaults to 2000)
34275 this.maxSize = 2000;
34278 * Whether to animate the transition to the new size
34281 this.animate = false;
34284 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34287 this.useShim = false;
34292 if(!cfg.existingProxy){
34294 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34296 this.proxy = Roo.get(cfg.existingProxy).dom;
34299 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34302 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34305 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34308 this.dragSpecs = {};
34311 * @private The adapter to use to positon and resize elements
34313 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34314 this.adapter.init(this);
34316 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34318 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34319 this.el.addClass("roo-splitbar-h");
34322 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34323 this.el.addClass("roo-splitbar-v");
34329 * Fires when the splitter is moved (alias for {@link #event-moved})
34330 * @param {Roo.bootstrap.SplitBar} this
34331 * @param {Number} newSize the new width or height
34336 * Fires when the splitter is moved
34337 * @param {Roo.bootstrap.SplitBar} this
34338 * @param {Number} newSize the new width or height
34342 * @event beforeresize
34343 * Fires before the splitter is dragged
34344 * @param {Roo.bootstrap.SplitBar} this
34346 "beforeresize" : true,
34348 "beforeapply" : true
34351 Roo.util.Observable.call(this);
34354 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34355 onStartProxyDrag : function(x, y){
34356 this.fireEvent("beforeresize", this);
34358 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34360 o.enableDisplayMode("block");
34361 // all splitbars share the same overlay
34362 Roo.bootstrap.SplitBar.prototype.overlay = o;
34364 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34365 this.overlay.show();
34366 Roo.get(this.proxy).setDisplayed("block");
34367 var size = this.adapter.getElementSize(this);
34368 this.activeMinSize = this.getMinimumSize();;
34369 this.activeMaxSize = this.getMaximumSize();;
34370 var c1 = size - this.activeMinSize;
34371 var c2 = Math.max(this.activeMaxSize - size, 0);
34372 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34373 this.dd.resetConstraints();
34374 this.dd.setXConstraint(
34375 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34376 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34378 this.dd.setYConstraint(0, 0);
34380 this.dd.resetConstraints();
34381 this.dd.setXConstraint(0, 0);
34382 this.dd.setYConstraint(
34383 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34384 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34387 this.dragSpecs.startSize = size;
34388 this.dragSpecs.startPoint = [x, y];
34389 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34393 * @private Called after the drag operation by the DDProxy
34395 onEndProxyDrag : function(e){
34396 Roo.get(this.proxy).setDisplayed(false);
34397 var endPoint = Roo.lib.Event.getXY(e);
34399 this.overlay.hide();
34402 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34403 newSize = this.dragSpecs.startSize +
34404 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34405 endPoint[0] - this.dragSpecs.startPoint[0] :
34406 this.dragSpecs.startPoint[0] - endPoint[0]
34409 newSize = this.dragSpecs.startSize +
34410 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34411 endPoint[1] - this.dragSpecs.startPoint[1] :
34412 this.dragSpecs.startPoint[1] - endPoint[1]
34415 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34416 if(newSize != this.dragSpecs.startSize){
34417 if(this.fireEvent('beforeapply', this, newSize) !== false){
34418 this.adapter.setElementSize(this, newSize);
34419 this.fireEvent("moved", this, newSize);
34420 this.fireEvent("resize", this, newSize);
34426 * Get the adapter this SplitBar uses
34427 * @return The adapter object
34429 getAdapter : function(){
34430 return this.adapter;
34434 * Set the adapter this SplitBar uses
34435 * @param {Object} adapter A SplitBar adapter object
34437 setAdapter : function(adapter){
34438 this.adapter = adapter;
34439 this.adapter.init(this);
34443 * Gets the minimum size for the resizing element
34444 * @return {Number} The minimum size
34446 getMinimumSize : function(){
34447 return this.minSize;
34451 * Sets the minimum size for the resizing element
34452 * @param {Number} minSize The minimum size
34454 setMinimumSize : function(minSize){
34455 this.minSize = minSize;
34459 * Gets the maximum size for the resizing element
34460 * @return {Number} The maximum size
34462 getMaximumSize : function(){
34463 return this.maxSize;
34467 * Sets the maximum size for the resizing element
34468 * @param {Number} maxSize The maximum size
34470 setMaximumSize : function(maxSize){
34471 this.maxSize = maxSize;
34475 * Sets the initialize size for the resizing element
34476 * @param {Number} size The initial size
34478 setCurrentSize : function(size){
34479 var oldAnimate = this.animate;
34480 this.animate = false;
34481 this.adapter.setElementSize(this, size);
34482 this.animate = oldAnimate;
34486 * Destroy this splitbar.
34487 * @param {Boolean} removeEl True to remove the element
34489 destroy : function(removeEl){
34491 this.shim.remove();
34494 this.proxy.parentNode.removeChild(this.proxy);
34502 * @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.
34504 Roo.bootstrap.SplitBar.createProxy = function(dir){
34505 var proxy = new Roo.Element(document.createElement("div"));
34506 proxy.unselectable();
34507 var cls = 'roo-splitbar-proxy';
34508 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34509 document.body.appendChild(proxy.dom);
34514 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34515 * Default Adapter. It assumes the splitter and resizing element are not positioned
34516 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34518 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34521 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34522 // do nothing for now
34523 init : function(s){
34527 * Called before drag operations to get the current size of the resizing element.
34528 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34530 getElementSize : function(s){
34531 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34532 return s.resizingEl.getWidth();
34534 return s.resizingEl.getHeight();
34539 * Called after drag operations to set the size of the resizing element.
34540 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34541 * @param {Number} newSize The new size to set
34542 * @param {Function} onComplete A function to be invoked when resizing is complete
34544 setElementSize : function(s, newSize, onComplete){
34545 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34547 s.resizingEl.setWidth(newSize);
34549 onComplete(s, newSize);
34552 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34557 s.resizingEl.setHeight(newSize);
34559 onComplete(s, newSize);
34562 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34569 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34570 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34571 * Adapter that moves the splitter element to align with the resized sizing element.
34572 * Used with an absolute positioned SplitBar.
34573 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34574 * document.body, make sure you assign an id to the body element.
34576 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34577 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34578 this.container = Roo.get(container);
34581 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34582 init : function(s){
34583 this.basic.init(s);
34586 getElementSize : function(s){
34587 return this.basic.getElementSize(s);
34590 setElementSize : function(s, newSize, onComplete){
34591 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34594 moveSplitter : function(s){
34595 var yes = Roo.bootstrap.SplitBar;
34596 switch(s.placement){
34598 s.el.setX(s.resizingEl.getRight());
34601 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34604 s.el.setY(s.resizingEl.getBottom());
34607 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34614 * Orientation constant - Create a vertical SplitBar
34618 Roo.bootstrap.SplitBar.VERTICAL = 1;
34621 * Orientation constant - Create a horizontal SplitBar
34625 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34628 * Placement constant - The resizing element is to the left of the splitter element
34632 Roo.bootstrap.SplitBar.LEFT = 1;
34635 * Placement constant - The resizing element is to the right of the splitter element
34639 Roo.bootstrap.SplitBar.RIGHT = 2;
34642 * Placement constant - The resizing element is positioned above the splitter element
34646 Roo.bootstrap.SplitBar.TOP = 3;
34649 * Placement constant - The resizing element is positioned under splitter element
34653 Roo.bootstrap.SplitBar.BOTTOM = 4;
34654 Roo.namespace("Roo.bootstrap.layout");/*
34656 * Ext JS Library 1.1.1
34657 * Copyright(c) 2006-2007, Ext JS, LLC.
34659 * Originally Released Under LGPL - original licence link has changed is not relivant.
34662 * <script type="text/javascript">
34666 * @class Roo.bootstrap.layout.Manager
34667 * @extends Roo.bootstrap.Component
34668 * Base class for layout managers.
34670 Roo.bootstrap.layout.Manager = function(config)
34672 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34678 /** false to disable window resize monitoring @type Boolean */
34679 this.monitorWindowResize = true;
34684 * Fires when a layout is performed.
34685 * @param {Roo.LayoutManager} this
34689 * @event regionresized
34690 * Fires when the user resizes a region.
34691 * @param {Roo.LayoutRegion} region The resized region
34692 * @param {Number} newSize The new size (width for east/west, height for north/south)
34694 "regionresized" : true,
34696 * @event regioncollapsed
34697 * Fires when a region is collapsed.
34698 * @param {Roo.LayoutRegion} region The collapsed region
34700 "regioncollapsed" : true,
34702 * @event regionexpanded
34703 * Fires when a region is expanded.
34704 * @param {Roo.LayoutRegion} region The expanded region
34706 "regionexpanded" : true
34708 this.updating = false;
34711 this.el = Roo.get(config.el);
34717 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34722 monitorWindowResize : true,
34728 onRender : function(ct, position)
34731 this.el = Roo.get(ct);
34734 //this.fireEvent('render',this);
34738 initEvents: function()
34742 // ie scrollbar fix
34743 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34744 document.body.scroll = "no";
34745 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34746 this.el.position('relative');
34748 this.id = this.el.id;
34749 this.el.addClass("roo-layout-container");
34750 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34751 if(this.el.dom != document.body ) {
34752 this.el.on('resize', this.layout,this);
34753 this.el.on('show', this.layout,this);
34759 * Returns true if this layout is currently being updated
34760 * @return {Boolean}
34762 isUpdating : function(){
34763 return this.updating;
34767 * Suspend the LayoutManager from doing auto-layouts while
34768 * making multiple add or remove calls
34770 beginUpdate : function(){
34771 this.updating = true;
34775 * Restore auto-layouts and optionally disable the manager from performing a layout
34776 * @param {Boolean} noLayout true to disable a layout update
34778 endUpdate : function(noLayout){
34779 this.updating = false;
34785 layout: function(){
34789 onRegionResized : function(region, newSize){
34790 this.fireEvent("regionresized", region, newSize);
34794 onRegionCollapsed : function(region){
34795 this.fireEvent("regioncollapsed", region);
34798 onRegionExpanded : function(region){
34799 this.fireEvent("regionexpanded", region);
34803 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34804 * performs box-model adjustments.
34805 * @return {Object} The size as an object {width: (the width), height: (the height)}
34807 getViewSize : function()
34810 if(this.el.dom != document.body){
34811 size = this.el.getSize();
34813 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34815 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34816 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34821 * Returns the Element this layout is bound to.
34822 * @return {Roo.Element}
34824 getEl : function(){
34829 * Returns the specified region.
34830 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34831 * @return {Roo.LayoutRegion}
34833 getRegion : function(target){
34834 return this.regions[target.toLowerCase()];
34837 onWindowResize : function(){
34838 if(this.monitorWindowResize){
34845 * Ext JS Library 1.1.1
34846 * Copyright(c) 2006-2007, Ext JS, LLC.
34848 * Originally Released Under LGPL - original licence link has changed is not relivant.
34851 * <script type="text/javascript">
34854 * @class Roo.bootstrap.layout.Border
34855 * @extends Roo.bootstrap.layout.Manager
34856 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34857 * please see: examples/bootstrap/nested.html<br><br>
34859 <b>The container the layout is rendered into can be either the body element or any other element.
34860 If it is not the body element, the container needs to either be an absolute positioned element,
34861 or you will need to add "position:relative" to the css of the container. You will also need to specify
34862 the container size if it is not the body element.</b>
34865 * Create a new Border
34866 * @param {Object} config Configuration options
34868 Roo.bootstrap.layout.Border = function(config){
34869 config = config || {};
34870 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34874 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34875 if(config[region]){
34876 config[region].region = region;
34877 this.addRegion(config[region]);
34883 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34885 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34887 * Creates and adds a new region if it doesn't already exist.
34888 * @param {String} target The target region key (north, south, east, west or center).
34889 * @param {Object} config The regions config object
34890 * @return {BorderLayoutRegion} The new region
34892 addRegion : function(config)
34894 if(!this.regions[config.region]){
34895 var r = this.factory(config);
34896 this.bindRegion(r);
34898 return this.regions[config.region];
34902 bindRegion : function(r){
34903 this.regions[r.config.region] = r;
34905 r.on("visibilitychange", this.layout, this);
34906 r.on("paneladded", this.layout, this);
34907 r.on("panelremoved", this.layout, this);
34908 r.on("invalidated", this.layout, this);
34909 r.on("resized", this.onRegionResized, this);
34910 r.on("collapsed", this.onRegionCollapsed, this);
34911 r.on("expanded", this.onRegionExpanded, this);
34915 * Performs a layout update.
34917 layout : function()
34919 if(this.updating) {
34923 // render all the rebions if they have not been done alreayd?
34924 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34925 if(this.regions[region] && !this.regions[region].bodyEl){
34926 this.regions[region].onRender(this.el)
34930 var size = this.getViewSize();
34931 var w = size.width;
34932 var h = size.height;
34937 //var x = 0, y = 0;
34939 var rs = this.regions;
34940 var north = rs["north"];
34941 var south = rs["south"];
34942 var west = rs["west"];
34943 var east = rs["east"];
34944 var center = rs["center"];
34945 //if(this.hideOnLayout){ // not supported anymore
34946 //c.el.setStyle("display", "none");
34948 if(north && north.isVisible()){
34949 var b = north.getBox();
34950 var m = north.getMargins();
34951 b.width = w - (m.left+m.right);
34954 centerY = b.height + b.y + m.bottom;
34955 centerH -= centerY;
34956 north.updateBox(this.safeBox(b));
34958 if(south && south.isVisible()){
34959 var b = south.getBox();
34960 var m = south.getMargins();
34961 b.width = w - (m.left+m.right);
34963 var totalHeight = (b.height + m.top + m.bottom);
34964 b.y = h - totalHeight + m.top;
34965 centerH -= totalHeight;
34966 south.updateBox(this.safeBox(b));
34968 if(west && west.isVisible()){
34969 var b = west.getBox();
34970 var m = west.getMargins();
34971 b.height = centerH - (m.top+m.bottom);
34973 b.y = centerY + m.top;
34974 var totalWidth = (b.width + m.left + m.right);
34975 centerX += totalWidth;
34976 centerW -= totalWidth;
34977 west.updateBox(this.safeBox(b));
34979 if(east && east.isVisible()){
34980 var b = east.getBox();
34981 var m = east.getMargins();
34982 b.height = centerH - (m.top+m.bottom);
34983 var totalWidth = (b.width + m.left + m.right);
34984 b.x = w - totalWidth + m.left;
34985 b.y = centerY + m.top;
34986 centerW -= totalWidth;
34987 east.updateBox(this.safeBox(b));
34990 var m = center.getMargins();
34992 x: centerX + m.left,
34993 y: centerY + m.top,
34994 width: centerW - (m.left+m.right),
34995 height: centerH - (m.top+m.bottom)
34997 //if(this.hideOnLayout){
34998 //center.el.setStyle("display", "block");
35000 center.updateBox(this.safeBox(centerBox));
35003 this.fireEvent("layout", this);
35007 safeBox : function(box){
35008 box.width = Math.max(0, box.width);
35009 box.height = Math.max(0, box.height);
35014 * Adds a ContentPanel (or subclass) to this layout.
35015 * @param {String} target The target region key (north, south, east, west or center).
35016 * @param {Roo.ContentPanel} panel The panel to add
35017 * @return {Roo.ContentPanel} The added panel
35019 add : function(target, panel){
35021 target = target.toLowerCase();
35022 return this.regions[target].add(panel);
35026 * Remove a ContentPanel (or subclass) to this layout.
35027 * @param {String} target The target region key (north, south, east, west or center).
35028 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35029 * @return {Roo.ContentPanel} The removed panel
35031 remove : function(target, panel){
35032 target = target.toLowerCase();
35033 return this.regions[target].remove(panel);
35037 * Searches all regions for a panel with the specified id
35038 * @param {String} panelId
35039 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35041 findPanel : function(panelId){
35042 var rs = this.regions;
35043 for(var target in rs){
35044 if(typeof rs[target] != "function"){
35045 var p = rs[target].getPanel(panelId);
35055 * Searches all regions for a panel with the specified id and activates (shows) it.
35056 * @param {String/ContentPanel} panelId The panels id or the panel itself
35057 * @return {Roo.ContentPanel} The shown panel or null
35059 showPanel : function(panelId) {
35060 var rs = this.regions;
35061 for(var target in rs){
35062 var r = rs[target];
35063 if(typeof r != "function"){
35064 if(r.hasPanel(panelId)){
35065 return r.showPanel(panelId);
35073 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35074 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35077 restoreState : function(provider){
35079 provider = Roo.state.Manager;
35081 var sm = new Roo.LayoutStateManager();
35082 sm.init(this, provider);
35088 * Adds a xtype elements to the layout.
35092 xtype : 'ContentPanel',
35099 xtype : 'NestedLayoutPanel',
35105 items : [ ... list of content panels or nested layout panels.. ]
35109 * @param {Object} cfg Xtype definition of item to add.
35111 addxtype : function(cfg)
35113 // basically accepts a pannel...
35114 // can accept a layout region..!?!?
35115 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35118 // theory? children can only be panels??
35120 //if (!cfg.xtype.match(/Panel$/)) {
35125 if (typeof(cfg.region) == 'undefined') {
35126 Roo.log("Failed to add Panel, region was not set");
35130 var region = cfg.region;
35136 xitems = cfg.items;
35143 case 'Content': // ContentPanel (el, cfg)
35144 case 'Scroll': // ContentPanel (el, cfg)
35146 cfg.autoCreate = true;
35147 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35149 // var el = this.el.createChild();
35150 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35153 this.add(region, ret);
35157 case 'TreePanel': // our new panel!
35158 cfg.el = this.el.createChild();
35159 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35160 this.add(region, ret);
35165 // create a new Layout (which is a Border Layout...
35167 var clayout = cfg.layout;
35168 clayout.el = this.el.createChild();
35169 clayout.items = clayout.items || [];
35173 // replace this exitems with the clayout ones..
35174 xitems = clayout.items;
35176 // force background off if it's in center...
35177 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35178 cfg.background = false;
35180 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35183 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35184 //console.log('adding nested layout panel ' + cfg.toSource());
35185 this.add(region, ret);
35186 nb = {}; /// find first...
35191 // needs grid and region
35193 //var el = this.getRegion(region).el.createChild();
35195 *var el = this.el.createChild();
35196 // create the grid first...
35197 cfg.grid.container = el;
35198 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35201 if (region == 'center' && this.active ) {
35202 cfg.background = false;
35205 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35207 this.add(region, ret);
35209 if (cfg.background) {
35210 // render grid on panel activation (if panel background)
35211 ret.on('activate', function(gp) {
35212 if (!gp.grid.rendered) {
35213 // gp.grid.render(el);
35217 // cfg.grid.render(el);
35223 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35224 // it was the old xcomponent building that caused this before.
35225 // espeically if border is the top element in the tree.
35235 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35237 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35238 this.add(region, ret);
35242 throw "Can not add '" + cfg.xtype + "' to Border";
35248 this.beginUpdate();
35252 Roo.each(xitems, function(i) {
35253 region = nb && i.region ? i.region : false;
35255 var add = ret.addxtype(i);
35258 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35259 if (!i.background) {
35260 abn[region] = nb[region] ;
35267 // make the last non-background panel active..
35268 //if (nb) { Roo.log(abn); }
35271 for(var r in abn) {
35272 region = this.getRegion(r);
35274 // tried using nb[r], but it does not work..
35276 region.showPanel(abn[r]);
35287 factory : function(cfg)
35290 var validRegions = Roo.bootstrap.layout.Border.regions;
35292 var target = cfg.region;
35295 var r = Roo.bootstrap.layout;
35299 return new r.North(cfg);
35301 return new r.South(cfg);
35303 return new r.East(cfg);
35305 return new r.West(cfg);
35307 return new r.Center(cfg);
35309 throw 'Layout region "'+target+'" not supported.';
35316 * Ext JS Library 1.1.1
35317 * Copyright(c) 2006-2007, Ext JS, LLC.
35319 * Originally Released Under LGPL - original licence link has changed is not relivant.
35322 * <script type="text/javascript">
35326 * @class Roo.bootstrap.layout.Basic
35327 * @extends Roo.util.Observable
35328 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35329 * and does not have a titlebar, tabs or any other features. All it does is size and position
35330 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35331 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35332 * @cfg {string} region the region that it inhabits..
35333 * @cfg {bool} skipConfig skip config?
35337 Roo.bootstrap.layout.Basic = function(config){
35339 this.mgr = config.mgr;
35341 this.position = config.region;
35343 var skipConfig = config.skipConfig;
35347 * @scope Roo.BasicLayoutRegion
35351 * @event beforeremove
35352 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35353 * @param {Roo.LayoutRegion} this
35354 * @param {Roo.ContentPanel} panel The panel
35355 * @param {Object} e The cancel event object
35357 "beforeremove" : true,
35359 * @event invalidated
35360 * Fires when the layout for this region is changed.
35361 * @param {Roo.LayoutRegion} this
35363 "invalidated" : true,
35365 * @event visibilitychange
35366 * Fires when this region is shown or hidden
35367 * @param {Roo.LayoutRegion} this
35368 * @param {Boolean} visibility true or false
35370 "visibilitychange" : true,
35372 * @event paneladded
35373 * Fires when a panel is added.
35374 * @param {Roo.LayoutRegion} this
35375 * @param {Roo.ContentPanel} panel The panel
35377 "paneladded" : true,
35379 * @event panelremoved
35380 * Fires when a panel is removed.
35381 * @param {Roo.LayoutRegion} this
35382 * @param {Roo.ContentPanel} panel The panel
35384 "panelremoved" : true,
35386 * @event beforecollapse
35387 * Fires when this region before collapse.
35388 * @param {Roo.LayoutRegion} this
35390 "beforecollapse" : true,
35393 * Fires when this region is collapsed.
35394 * @param {Roo.LayoutRegion} this
35396 "collapsed" : true,
35399 * Fires when this region is expanded.
35400 * @param {Roo.LayoutRegion} this
35405 * Fires when this region is slid into view.
35406 * @param {Roo.LayoutRegion} this
35408 "slideshow" : true,
35411 * Fires when this region slides out of view.
35412 * @param {Roo.LayoutRegion} this
35414 "slidehide" : true,
35416 * @event panelactivated
35417 * Fires when a panel is activated.
35418 * @param {Roo.LayoutRegion} this
35419 * @param {Roo.ContentPanel} panel The activated panel
35421 "panelactivated" : true,
35424 * Fires when the user resizes this region.
35425 * @param {Roo.LayoutRegion} this
35426 * @param {Number} newSize The new size (width for east/west, height for north/south)
35430 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35431 this.panels = new Roo.util.MixedCollection();
35432 this.panels.getKey = this.getPanelId.createDelegate(this);
35434 this.activePanel = null;
35435 // ensure listeners are added...
35437 if (config.listeners || config.events) {
35438 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35439 listeners : config.listeners || {},
35440 events : config.events || {}
35444 if(skipConfig !== true){
35445 this.applyConfig(config);
35449 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35451 getPanelId : function(p){
35455 applyConfig : function(config){
35456 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35457 this.config = config;
35462 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35463 * the width, for horizontal (north, south) the height.
35464 * @param {Number} newSize The new width or height
35466 resizeTo : function(newSize){
35467 var el = this.el ? this.el :
35468 (this.activePanel ? this.activePanel.getEl() : null);
35470 switch(this.position){
35473 el.setWidth(newSize);
35474 this.fireEvent("resized", this, newSize);
35478 el.setHeight(newSize);
35479 this.fireEvent("resized", this, newSize);
35485 getBox : function(){
35486 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35489 getMargins : function(){
35490 return this.margins;
35493 updateBox : function(box){
35495 var el = this.activePanel.getEl();
35496 el.dom.style.left = box.x + "px";
35497 el.dom.style.top = box.y + "px";
35498 this.activePanel.setSize(box.width, box.height);
35502 * Returns the container element for this region.
35503 * @return {Roo.Element}
35505 getEl : function(){
35506 return this.activePanel;
35510 * Returns true if this region is currently visible.
35511 * @return {Boolean}
35513 isVisible : function(){
35514 return this.activePanel ? true : false;
35517 setActivePanel : function(panel){
35518 panel = this.getPanel(panel);
35519 if(this.activePanel && this.activePanel != panel){
35520 this.activePanel.setActiveState(false);
35521 this.activePanel.getEl().setLeftTop(-10000,-10000);
35523 this.activePanel = panel;
35524 panel.setActiveState(true);
35526 panel.setSize(this.box.width, this.box.height);
35528 this.fireEvent("panelactivated", this, panel);
35529 this.fireEvent("invalidated");
35533 * Show the specified panel.
35534 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35535 * @return {Roo.ContentPanel} The shown panel or null
35537 showPanel : function(panel){
35538 panel = this.getPanel(panel);
35540 this.setActivePanel(panel);
35546 * Get the active panel for this region.
35547 * @return {Roo.ContentPanel} The active panel or null
35549 getActivePanel : function(){
35550 return this.activePanel;
35554 * Add the passed ContentPanel(s)
35555 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35556 * @return {Roo.ContentPanel} The panel added (if only one was added)
35558 add : function(panel){
35559 if(arguments.length > 1){
35560 for(var i = 0, len = arguments.length; i < len; i++) {
35561 this.add(arguments[i]);
35565 if(this.hasPanel(panel)){
35566 this.showPanel(panel);
35569 var el = panel.getEl();
35570 if(el.dom.parentNode != this.mgr.el.dom){
35571 this.mgr.el.dom.appendChild(el.dom);
35573 if(panel.setRegion){
35574 panel.setRegion(this);
35576 this.panels.add(panel);
35577 el.setStyle("position", "absolute");
35578 if(!panel.background){
35579 this.setActivePanel(panel);
35580 if(this.config.initialSize && this.panels.getCount()==1){
35581 this.resizeTo(this.config.initialSize);
35584 this.fireEvent("paneladded", this, panel);
35589 * Returns true if the panel is in this region.
35590 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35591 * @return {Boolean}
35593 hasPanel : function(panel){
35594 if(typeof panel == "object"){ // must be panel obj
35595 panel = panel.getId();
35597 return this.getPanel(panel) ? true : false;
35601 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35602 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35603 * @param {Boolean} preservePanel Overrides the config preservePanel option
35604 * @return {Roo.ContentPanel} The panel that was removed
35606 remove : function(panel, preservePanel){
35607 panel = this.getPanel(panel);
35612 this.fireEvent("beforeremove", this, panel, e);
35613 if(e.cancel === true){
35616 var panelId = panel.getId();
35617 this.panels.removeKey(panelId);
35622 * Returns the panel specified or null if it's not in this region.
35623 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35624 * @return {Roo.ContentPanel}
35626 getPanel : function(id){
35627 if(typeof id == "object"){ // must be panel obj
35630 return this.panels.get(id);
35634 * Returns this regions position (north/south/east/west/center).
35637 getPosition: function(){
35638 return this.position;
35642 * Ext JS Library 1.1.1
35643 * Copyright(c) 2006-2007, Ext JS, LLC.
35645 * Originally Released Under LGPL - original licence link has changed is not relivant.
35648 * <script type="text/javascript">
35652 * @class Roo.bootstrap.layout.Region
35653 * @extends Roo.bootstrap.layout.Basic
35654 * This class represents a region in a layout manager.
35656 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35657 * @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})
35658 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35659 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35660 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35661 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35662 * @cfg {String} title The title for the region (overrides panel titles)
35663 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35664 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35665 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35666 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35667 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35668 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35669 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35670 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35671 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35672 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35674 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35675 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35676 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35677 * @cfg {Number} width For East/West panels
35678 * @cfg {Number} height For North/South panels
35679 * @cfg {Boolean} split To show the splitter
35680 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35682 * @cfg {string} cls Extra CSS classes to add to region
35684 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35685 * @cfg {string} region the region that it inhabits..
35688 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35689 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35691 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35692 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35693 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35695 Roo.bootstrap.layout.Region = function(config)
35697 this.applyConfig(config);
35699 var mgr = config.mgr;
35700 var pos = config.region;
35701 config.skipConfig = true;
35702 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35705 this.onRender(mgr.el);
35708 this.visible = true;
35709 this.collapsed = false;
35710 this.unrendered_panels = [];
35713 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35715 position: '', // set by wrapper (eg. north/south etc..)
35716 unrendered_panels : null, // unrendered panels.
35717 createBody : function(){
35718 /** This region's body element
35719 * @type Roo.Element */
35720 this.bodyEl = this.el.createChild({
35722 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35726 onRender: function(ctr, pos)
35728 var dh = Roo.DomHelper;
35729 /** This region's container element
35730 * @type Roo.Element */
35731 this.el = dh.append(ctr.dom, {
35733 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35735 /** This region's title element
35736 * @type Roo.Element */
35738 this.titleEl = dh.append(this.el.dom,
35741 unselectable: "on",
35742 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35744 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35745 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35748 this.titleEl.enableDisplayMode();
35749 /** This region's title text element
35750 * @type HTMLElement */
35751 this.titleTextEl = this.titleEl.dom.firstChild;
35752 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35754 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35755 this.closeBtn.enableDisplayMode();
35756 this.closeBtn.on("click", this.closeClicked, this);
35757 this.closeBtn.hide();
35759 this.createBody(this.config);
35760 if(this.config.hideWhenEmpty){
35762 this.on("paneladded", this.validateVisibility, this);
35763 this.on("panelremoved", this.validateVisibility, this);
35765 if(this.autoScroll){
35766 this.bodyEl.setStyle("overflow", "auto");
35768 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35770 //if(c.titlebar !== false){
35771 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35772 this.titleEl.hide();
35774 this.titleEl.show();
35775 if(this.config.title){
35776 this.titleTextEl.innerHTML = this.config.title;
35780 if(this.config.collapsed){
35781 this.collapse(true);
35783 if(this.config.hidden){
35787 if (this.unrendered_panels && this.unrendered_panels.length) {
35788 for (var i =0;i< this.unrendered_panels.length; i++) {
35789 this.add(this.unrendered_panels[i]);
35791 this.unrendered_panels = null;
35797 applyConfig : function(c)
35800 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35801 var dh = Roo.DomHelper;
35802 if(c.titlebar !== false){
35803 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35804 this.collapseBtn.on("click", this.collapse, this);
35805 this.collapseBtn.enableDisplayMode();
35807 if(c.showPin === true || this.showPin){
35808 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35809 this.stickBtn.enableDisplayMode();
35810 this.stickBtn.on("click", this.expand, this);
35811 this.stickBtn.hide();
35816 /** This region's collapsed element
35817 * @type Roo.Element */
35820 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35821 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35824 if(c.floatable !== false){
35825 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35826 this.collapsedEl.on("click", this.collapseClick, this);
35829 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35830 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35831 id: "message", unselectable: "on", style:{"float":"left"}});
35832 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35834 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35835 this.expandBtn.on("click", this.expand, this);
35839 if(this.collapseBtn){
35840 this.collapseBtn.setVisible(c.collapsible == true);
35843 this.cmargins = c.cmargins || this.cmargins ||
35844 (this.position == "west" || this.position == "east" ?
35845 {top: 0, left: 2, right:2, bottom: 0} :
35846 {top: 2, left: 0, right:0, bottom: 2});
35848 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35851 this.bottomTabs = c.tabPosition != "top";
35853 this.autoScroll = c.autoScroll || false;
35858 this.duration = c.duration || .30;
35859 this.slideDuration = c.slideDuration || .45;
35864 * Returns true if this region is currently visible.
35865 * @return {Boolean}
35867 isVisible : function(){
35868 return this.visible;
35872 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35873 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35875 //setCollapsedTitle : function(title){
35876 // title = title || " ";
35877 // if(this.collapsedTitleTextEl){
35878 // this.collapsedTitleTextEl.innerHTML = title;
35882 getBox : function(){
35884 // if(!this.collapsed){
35885 b = this.el.getBox(false, true);
35887 // b = this.collapsedEl.getBox(false, true);
35892 getMargins : function(){
35893 return this.margins;
35894 //return this.collapsed ? this.cmargins : this.margins;
35897 highlight : function(){
35898 this.el.addClass("x-layout-panel-dragover");
35901 unhighlight : function(){
35902 this.el.removeClass("x-layout-panel-dragover");
35905 updateBox : function(box)
35907 if (!this.bodyEl) {
35908 return; // not rendered yet..
35912 if(!this.collapsed){
35913 this.el.dom.style.left = box.x + "px";
35914 this.el.dom.style.top = box.y + "px";
35915 this.updateBody(box.width, box.height);
35917 this.collapsedEl.dom.style.left = box.x + "px";
35918 this.collapsedEl.dom.style.top = box.y + "px";
35919 this.collapsedEl.setSize(box.width, box.height);
35922 this.tabs.autoSizeTabs();
35926 updateBody : function(w, h)
35929 this.el.setWidth(w);
35930 w -= this.el.getBorderWidth("rl");
35931 if(this.config.adjustments){
35932 w += this.config.adjustments[0];
35935 if(h !== null && h > 0){
35936 this.el.setHeight(h);
35937 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35938 h -= this.el.getBorderWidth("tb");
35939 if(this.config.adjustments){
35940 h += this.config.adjustments[1];
35942 this.bodyEl.setHeight(h);
35944 h = this.tabs.syncHeight(h);
35947 if(this.panelSize){
35948 w = w !== null ? w : this.panelSize.width;
35949 h = h !== null ? h : this.panelSize.height;
35951 if(this.activePanel){
35952 var el = this.activePanel.getEl();
35953 w = w !== null ? w : el.getWidth();
35954 h = h !== null ? h : el.getHeight();
35955 this.panelSize = {width: w, height: h};
35956 this.activePanel.setSize(w, h);
35958 if(Roo.isIE && this.tabs){
35959 this.tabs.el.repaint();
35964 * Returns the container element for this region.
35965 * @return {Roo.Element}
35967 getEl : function(){
35972 * Hides this region.
35975 //if(!this.collapsed){
35976 this.el.dom.style.left = "-2000px";
35979 // this.collapsedEl.dom.style.left = "-2000px";
35980 // this.collapsedEl.hide();
35982 this.visible = false;
35983 this.fireEvent("visibilitychange", this, false);
35987 * Shows this region if it was previously hidden.
35990 //if(!this.collapsed){
35993 // this.collapsedEl.show();
35995 this.visible = true;
35996 this.fireEvent("visibilitychange", this, true);
35999 closeClicked : function(){
36000 if(this.activePanel){
36001 this.remove(this.activePanel);
36005 collapseClick : function(e){
36007 e.stopPropagation();
36010 e.stopPropagation();
36016 * Collapses this region.
36017 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36020 collapse : function(skipAnim, skipCheck = false){
36021 if(this.collapsed) {
36025 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36027 this.collapsed = true;
36029 this.split.el.hide();
36031 if(this.config.animate && skipAnim !== true){
36032 this.fireEvent("invalidated", this);
36033 this.animateCollapse();
36035 this.el.setLocation(-20000,-20000);
36037 this.collapsedEl.show();
36038 this.fireEvent("collapsed", this);
36039 this.fireEvent("invalidated", this);
36045 animateCollapse : function(){
36050 * Expands this region if it was previously collapsed.
36051 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36052 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36055 expand : function(e, skipAnim){
36057 e.stopPropagation();
36059 if(!this.collapsed || this.el.hasActiveFx()) {
36063 this.afterSlideIn();
36066 this.collapsed = false;
36067 if(this.config.animate && skipAnim !== true){
36068 this.animateExpand();
36072 this.split.el.show();
36074 this.collapsedEl.setLocation(-2000,-2000);
36075 this.collapsedEl.hide();
36076 this.fireEvent("invalidated", this);
36077 this.fireEvent("expanded", this);
36081 animateExpand : function(){
36085 initTabs : function()
36087 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36089 var ts = new Roo.bootstrap.panel.Tabs({
36090 el: this.bodyEl.dom,
36091 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36092 disableTooltips: this.config.disableTabTips,
36093 toolbar : this.config.toolbar
36096 if(this.config.hideTabs){
36097 ts.stripWrap.setDisplayed(false);
36100 ts.resizeTabs = this.config.resizeTabs === true;
36101 ts.minTabWidth = this.config.minTabWidth || 40;
36102 ts.maxTabWidth = this.config.maxTabWidth || 250;
36103 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36104 ts.monitorResize = false;
36105 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36106 ts.bodyEl.addClass('roo-layout-tabs-body');
36107 this.panels.each(this.initPanelAsTab, this);
36110 initPanelAsTab : function(panel){
36111 var ti = this.tabs.addTab(
36115 this.config.closeOnTab && panel.isClosable(),
36118 if(panel.tabTip !== undefined){
36119 ti.setTooltip(panel.tabTip);
36121 ti.on("activate", function(){
36122 this.setActivePanel(panel);
36125 if(this.config.closeOnTab){
36126 ti.on("beforeclose", function(t, e){
36128 this.remove(panel);
36132 panel.tabItem = ti;
36137 updatePanelTitle : function(panel, title)
36139 if(this.activePanel == panel){
36140 this.updateTitle(title);
36143 var ti = this.tabs.getTab(panel.getEl().id);
36145 if(panel.tabTip !== undefined){
36146 ti.setTooltip(panel.tabTip);
36151 updateTitle : function(title){
36152 if(this.titleTextEl && !this.config.title){
36153 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36157 setActivePanel : function(panel)
36159 panel = this.getPanel(panel);
36160 if(this.activePanel && this.activePanel != panel){
36161 if(this.activePanel.setActiveState(false) === false){
36165 this.activePanel = panel;
36166 panel.setActiveState(true);
36167 if(this.panelSize){
36168 panel.setSize(this.panelSize.width, this.panelSize.height);
36171 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36173 this.updateTitle(panel.getTitle());
36175 this.fireEvent("invalidated", this);
36177 this.fireEvent("panelactivated", this, panel);
36181 * Shows the specified panel.
36182 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36183 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36185 showPanel : function(panel)
36187 panel = this.getPanel(panel);
36190 var tab = this.tabs.getTab(panel.getEl().id);
36191 if(tab.isHidden()){
36192 this.tabs.unhideTab(tab.id);
36196 this.setActivePanel(panel);
36203 * Get the active panel for this region.
36204 * @return {Roo.ContentPanel} The active panel or null
36206 getActivePanel : function(){
36207 return this.activePanel;
36210 validateVisibility : function(){
36211 if(this.panels.getCount() < 1){
36212 this.updateTitle(" ");
36213 this.closeBtn.hide();
36216 if(!this.isVisible()){
36223 * Adds the passed ContentPanel(s) to this region.
36224 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36225 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36227 add : function(panel)
36229 if(arguments.length > 1){
36230 for(var i = 0, len = arguments.length; i < len; i++) {
36231 this.add(arguments[i]);
36236 // if we have not been rendered yet, then we can not really do much of this..
36237 if (!this.bodyEl) {
36238 this.unrendered_panels.push(panel);
36245 if(this.hasPanel(panel)){
36246 this.showPanel(panel);
36249 panel.setRegion(this);
36250 this.panels.add(panel);
36251 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36252 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36253 // and hide them... ???
36254 this.bodyEl.dom.appendChild(panel.getEl().dom);
36255 if(panel.background !== true){
36256 this.setActivePanel(panel);
36258 this.fireEvent("paneladded", this, panel);
36265 this.initPanelAsTab(panel);
36269 if(panel.background !== true){
36270 this.tabs.activate(panel.getEl().id);
36272 this.fireEvent("paneladded", this, panel);
36277 * Hides the tab for the specified panel.
36278 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36280 hidePanel : function(panel){
36281 if(this.tabs && (panel = this.getPanel(panel))){
36282 this.tabs.hideTab(panel.getEl().id);
36287 * Unhides the tab for a previously hidden panel.
36288 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36290 unhidePanel : function(panel){
36291 if(this.tabs && (panel = this.getPanel(panel))){
36292 this.tabs.unhideTab(panel.getEl().id);
36296 clearPanels : function(){
36297 while(this.panels.getCount() > 0){
36298 this.remove(this.panels.first());
36303 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36304 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36305 * @param {Boolean} preservePanel Overrides the config preservePanel option
36306 * @return {Roo.ContentPanel} The panel that was removed
36308 remove : function(panel, preservePanel)
36310 panel = this.getPanel(panel);
36315 this.fireEvent("beforeremove", this, panel, e);
36316 if(e.cancel === true){
36319 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36320 var panelId = panel.getId();
36321 this.panels.removeKey(panelId);
36323 document.body.appendChild(panel.getEl().dom);
36326 this.tabs.removeTab(panel.getEl().id);
36327 }else if (!preservePanel){
36328 this.bodyEl.dom.removeChild(panel.getEl().dom);
36330 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36331 var p = this.panels.first();
36332 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36333 tempEl.appendChild(p.getEl().dom);
36334 this.bodyEl.update("");
36335 this.bodyEl.dom.appendChild(p.getEl().dom);
36337 this.updateTitle(p.getTitle());
36339 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36340 this.setActivePanel(p);
36342 panel.setRegion(null);
36343 if(this.activePanel == panel){
36344 this.activePanel = null;
36346 if(this.config.autoDestroy !== false && preservePanel !== true){
36347 try{panel.destroy();}catch(e){}
36349 this.fireEvent("panelremoved", this, panel);
36354 * Returns the TabPanel component used by this region
36355 * @return {Roo.TabPanel}
36357 getTabs : function(){
36361 createTool : function(parentEl, className){
36362 var btn = Roo.DomHelper.append(parentEl, {
36364 cls: "x-layout-tools-button",
36367 cls: "roo-layout-tools-button-inner " + className,
36371 btn.addClassOnOver("roo-layout-tools-button-over");
36376 * Ext JS Library 1.1.1
36377 * Copyright(c) 2006-2007, Ext JS, LLC.
36379 * Originally Released Under LGPL - original licence link has changed is not relivant.
36382 * <script type="text/javascript">
36388 * @class Roo.SplitLayoutRegion
36389 * @extends Roo.LayoutRegion
36390 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36392 Roo.bootstrap.layout.Split = function(config){
36393 this.cursor = config.cursor;
36394 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36397 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36399 splitTip : "Drag to resize.",
36400 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36401 useSplitTips : false,
36403 applyConfig : function(config){
36404 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36407 onRender : function(ctr,pos) {
36409 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36410 if(!this.config.split){
36415 var splitEl = Roo.DomHelper.append(ctr.dom, {
36417 id: this.el.id + "-split",
36418 cls: "roo-layout-split roo-layout-split-"+this.position,
36421 /** The SplitBar for this region
36422 * @type Roo.SplitBar */
36423 // does not exist yet...
36424 Roo.log([this.position, this.orientation]);
36426 this.split = new Roo.bootstrap.SplitBar({
36427 dragElement : splitEl,
36428 resizingElement: this.el,
36429 orientation : this.orientation
36432 this.split.on("moved", this.onSplitMove, this);
36433 this.split.useShim = this.config.useShim === true;
36434 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36435 if(this.useSplitTips){
36436 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36438 //if(config.collapsible){
36439 // this.split.el.on("dblclick", this.collapse, this);
36442 if(typeof this.config.minSize != "undefined"){
36443 this.split.minSize = this.config.minSize;
36445 if(typeof this.config.maxSize != "undefined"){
36446 this.split.maxSize = this.config.maxSize;
36448 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36449 this.hideSplitter();
36454 getHMaxSize : function(){
36455 var cmax = this.config.maxSize || 10000;
36456 var center = this.mgr.getRegion("center");
36457 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36460 getVMaxSize : function(){
36461 var cmax = this.config.maxSize || 10000;
36462 var center = this.mgr.getRegion("center");
36463 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36466 onSplitMove : function(split, newSize){
36467 this.fireEvent("resized", this, newSize);
36471 * Returns the {@link Roo.SplitBar} for this region.
36472 * @return {Roo.SplitBar}
36474 getSplitBar : function(){
36479 this.hideSplitter();
36480 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36483 hideSplitter : function(){
36485 this.split.el.setLocation(-2000,-2000);
36486 this.split.el.hide();
36492 this.split.el.show();
36494 Roo.bootstrap.layout.Split.superclass.show.call(this);
36497 beforeSlide: function(){
36498 if(Roo.isGecko){// firefox overflow auto bug workaround
36499 this.bodyEl.clip();
36501 this.tabs.bodyEl.clip();
36503 if(this.activePanel){
36504 this.activePanel.getEl().clip();
36506 if(this.activePanel.beforeSlide){
36507 this.activePanel.beforeSlide();
36513 afterSlide : function(){
36514 if(Roo.isGecko){// firefox overflow auto bug workaround
36515 this.bodyEl.unclip();
36517 this.tabs.bodyEl.unclip();
36519 if(this.activePanel){
36520 this.activePanel.getEl().unclip();
36521 if(this.activePanel.afterSlide){
36522 this.activePanel.afterSlide();
36528 initAutoHide : function(){
36529 if(this.autoHide !== false){
36530 if(!this.autoHideHd){
36531 var st = new Roo.util.DelayedTask(this.slideIn, this);
36532 this.autoHideHd = {
36533 "mouseout": function(e){
36534 if(!e.within(this.el, true)){
36538 "mouseover" : function(e){
36544 this.el.on(this.autoHideHd);
36548 clearAutoHide : function(){
36549 if(this.autoHide !== false){
36550 this.el.un("mouseout", this.autoHideHd.mouseout);
36551 this.el.un("mouseover", this.autoHideHd.mouseover);
36555 clearMonitor : function(){
36556 Roo.get(document).un("click", this.slideInIf, this);
36559 // these names are backwards but not changed for compat
36560 slideOut : function(){
36561 if(this.isSlid || this.el.hasActiveFx()){
36564 this.isSlid = true;
36565 if(this.collapseBtn){
36566 this.collapseBtn.hide();
36568 this.closeBtnState = this.closeBtn.getStyle('display');
36569 this.closeBtn.hide();
36571 this.stickBtn.show();
36574 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36575 this.beforeSlide();
36576 this.el.setStyle("z-index", 10001);
36577 this.el.slideIn(this.getSlideAnchor(), {
36578 callback: function(){
36580 this.initAutoHide();
36581 Roo.get(document).on("click", this.slideInIf, this);
36582 this.fireEvent("slideshow", this);
36589 afterSlideIn : function(){
36590 this.clearAutoHide();
36591 this.isSlid = false;
36592 this.clearMonitor();
36593 this.el.setStyle("z-index", "");
36594 if(this.collapseBtn){
36595 this.collapseBtn.show();
36597 this.closeBtn.setStyle('display', this.closeBtnState);
36599 this.stickBtn.hide();
36601 this.fireEvent("slidehide", this);
36604 slideIn : function(cb){
36605 if(!this.isSlid || this.el.hasActiveFx()){
36609 this.isSlid = false;
36610 this.beforeSlide();
36611 this.el.slideOut(this.getSlideAnchor(), {
36612 callback: function(){
36613 this.el.setLeftTop(-10000, -10000);
36615 this.afterSlideIn();
36623 slideInIf : function(e){
36624 if(!e.within(this.el)){
36629 animateCollapse : function(){
36630 this.beforeSlide();
36631 this.el.setStyle("z-index", 20000);
36632 var anchor = this.getSlideAnchor();
36633 this.el.slideOut(anchor, {
36634 callback : function(){
36635 this.el.setStyle("z-index", "");
36636 this.collapsedEl.slideIn(anchor, {duration:.3});
36638 this.el.setLocation(-10000,-10000);
36640 this.fireEvent("collapsed", this);
36647 animateExpand : function(){
36648 this.beforeSlide();
36649 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36650 this.el.setStyle("z-index", 20000);
36651 this.collapsedEl.hide({
36654 this.el.slideIn(this.getSlideAnchor(), {
36655 callback : function(){
36656 this.el.setStyle("z-index", "");
36659 this.split.el.show();
36661 this.fireEvent("invalidated", this);
36662 this.fireEvent("expanded", this);
36690 getAnchor : function(){
36691 return this.anchors[this.position];
36694 getCollapseAnchor : function(){
36695 return this.canchors[this.position];
36698 getSlideAnchor : function(){
36699 return this.sanchors[this.position];
36702 getAlignAdj : function(){
36703 var cm = this.cmargins;
36704 switch(this.position){
36720 getExpandAdj : function(){
36721 var c = this.collapsedEl, cm = this.cmargins;
36722 switch(this.position){
36724 return [-(cm.right+c.getWidth()+cm.left), 0];
36727 return [cm.right+c.getWidth()+cm.left, 0];
36730 return [0, -(cm.top+cm.bottom+c.getHeight())];
36733 return [0, cm.top+cm.bottom+c.getHeight()];
36739 * Ext JS Library 1.1.1
36740 * Copyright(c) 2006-2007, Ext JS, LLC.
36742 * Originally Released Under LGPL - original licence link has changed is not relivant.
36745 * <script type="text/javascript">
36748 * These classes are private internal classes
36750 Roo.bootstrap.layout.Center = function(config){
36751 config.region = "center";
36752 Roo.bootstrap.layout.Region.call(this, config);
36753 this.visible = true;
36754 this.minWidth = config.minWidth || 20;
36755 this.minHeight = config.minHeight || 20;
36758 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36760 // center panel can't be hidden
36764 // center panel can't be hidden
36767 getMinWidth: function(){
36768 return this.minWidth;
36771 getMinHeight: function(){
36772 return this.minHeight;
36785 Roo.bootstrap.layout.North = function(config)
36787 config.region = 'north';
36788 config.cursor = 'n-resize';
36790 Roo.bootstrap.layout.Split.call(this, config);
36794 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36795 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36796 this.split.el.addClass("roo-layout-split-v");
36798 var size = config.initialSize || config.height;
36799 if(typeof size != "undefined"){
36800 this.el.setHeight(size);
36803 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36805 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36809 getBox : function(){
36810 if(this.collapsed){
36811 return this.collapsedEl.getBox();
36813 var box = this.el.getBox();
36815 box.height += this.split.el.getHeight();
36820 updateBox : function(box){
36821 if(this.split && !this.collapsed){
36822 box.height -= this.split.el.getHeight();
36823 this.split.el.setLeft(box.x);
36824 this.split.el.setTop(box.y+box.height);
36825 this.split.el.setWidth(box.width);
36827 if(this.collapsed){
36828 this.updateBody(box.width, null);
36830 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36838 Roo.bootstrap.layout.South = function(config){
36839 config.region = 'south';
36840 config.cursor = 's-resize';
36841 Roo.bootstrap.layout.Split.call(this, config);
36843 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36844 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36845 this.split.el.addClass("roo-layout-split-v");
36847 var size = config.initialSize || config.height;
36848 if(typeof size != "undefined"){
36849 this.el.setHeight(size);
36853 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36854 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36855 getBox : function(){
36856 if(this.collapsed){
36857 return this.collapsedEl.getBox();
36859 var box = this.el.getBox();
36861 var sh = this.split.el.getHeight();
36868 updateBox : function(box){
36869 if(this.split && !this.collapsed){
36870 var sh = this.split.el.getHeight();
36873 this.split.el.setLeft(box.x);
36874 this.split.el.setTop(box.y-sh);
36875 this.split.el.setWidth(box.width);
36877 if(this.collapsed){
36878 this.updateBody(box.width, null);
36880 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36884 Roo.bootstrap.layout.East = function(config){
36885 config.region = "east";
36886 config.cursor = "e-resize";
36887 Roo.bootstrap.layout.Split.call(this, config);
36889 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36890 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36891 this.split.el.addClass("roo-layout-split-h");
36893 var size = config.initialSize || config.width;
36894 if(typeof size != "undefined"){
36895 this.el.setWidth(size);
36898 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36899 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36900 getBox : function(){
36901 if(this.collapsed){
36902 return this.collapsedEl.getBox();
36904 var box = this.el.getBox();
36906 var sw = this.split.el.getWidth();
36913 updateBox : function(box){
36914 if(this.split && !this.collapsed){
36915 var sw = this.split.el.getWidth();
36917 this.split.el.setLeft(box.x);
36918 this.split.el.setTop(box.y);
36919 this.split.el.setHeight(box.height);
36922 if(this.collapsed){
36923 this.updateBody(null, box.height);
36925 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36929 Roo.bootstrap.layout.West = function(config){
36930 config.region = "west";
36931 config.cursor = "w-resize";
36933 Roo.bootstrap.layout.Split.call(this, config);
36935 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36936 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36937 this.split.el.addClass("roo-layout-split-h");
36941 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36942 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36944 onRender: function(ctr, pos)
36946 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36947 var size = this.config.initialSize || this.config.width;
36948 if(typeof size != "undefined"){
36949 this.el.setWidth(size);
36953 getBox : function(){
36954 if(this.collapsed){
36955 return this.collapsedEl.getBox();
36957 var box = this.el.getBox();
36959 box.width += this.split.el.getWidth();
36964 updateBox : function(box){
36965 if(this.split && !this.collapsed){
36966 var sw = this.split.el.getWidth();
36968 this.split.el.setLeft(box.x+box.width);
36969 this.split.el.setTop(box.y);
36970 this.split.el.setHeight(box.height);
36972 if(this.collapsed){
36973 this.updateBody(null, box.height);
36975 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36978 Roo.namespace("Roo.bootstrap.panel");/*
36980 * Ext JS Library 1.1.1
36981 * Copyright(c) 2006-2007, Ext JS, LLC.
36983 * Originally Released Under LGPL - original licence link has changed is not relivant.
36986 * <script type="text/javascript">
36989 * @class Roo.ContentPanel
36990 * @extends Roo.util.Observable
36991 * A basic ContentPanel element.
36992 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
36993 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
36994 * @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
36995 * @cfg {Boolean} closable True if the panel can be closed/removed
36996 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
36997 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36998 * @cfg {Toolbar} toolbar A toolbar for this panel
36999 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37000 * @cfg {String} title The title for this panel
37001 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37002 * @cfg {String} url Calls {@link #setUrl} with this value
37003 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37004 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37005 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37006 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37007 * @cfg {Boolean} badges render the badges
37010 * Create a new ContentPanel.
37011 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37012 * @param {String/Object} config A string to set only the title or a config object
37013 * @param {String} content (optional) Set the HTML content for this panel
37014 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37016 Roo.bootstrap.panel.Content = function( config){
37018 this.tpl = config.tpl || false;
37020 var el = config.el;
37021 var content = config.content;
37023 if(config.autoCreate){ // xtype is available if this is called from factory
37026 this.el = Roo.get(el);
37027 if(!this.el && config && config.autoCreate){
37028 if(typeof config.autoCreate == "object"){
37029 if(!config.autoCreate.id){
37030 config.autoCreate.id = config.id||el;
37032 this.el = Roo.DomHelper.append(document.body,
37033 config.autoCreate, true);
37035 var elcfg = { tag: "div",
37036 cls: "roo-layout-inactive-content",
37040 elcfg.html = config.html;
37044 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37047 this.closable = false;
37048 this.loaded = false;
37049 this.active = false;
37052 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37054 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37056 this.wrapEl = this.el; //this.el.wrap();
37058 if (config.toolbar.items) {
37059 ti = config.toolbar.items ;
37060 delete config.toolbar.items ;
37064 this.toolbar.render(this.wrapEl, 'before');
37065 for(var i =0;i < ti.length;i++) {
37066 // Roo.log(['add child', items[i]]);
37067 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37069 this.toolbar.items = nitems;
37070 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37071 delete config.toolbar;
37075 // xtype created footer. - not sure if will work as we normally have to render first..
37076 if (this.footer && !this.footer.el && this.footer.xtype) {
37077 if (!this.wrapEl) {
37078 this.wrapEl = this.el.wrap();
37081 this.footer.container = this.wrapEl.createChild();
37083 this.footer = Roo.factory(this.footer, Roo);
37088 if(typeof config == "string"){
37089 this.title = config;
37091 Roo.apply(this, config);
37095 this.resizeEl = Roo.get(this.resizeEl, true);
37097 this.resizeEl = this.el;
37099 // handle view.xtype
37107 * Fires when this panel is activated.
37108 * @param {Roo.ContentPanel} this
37112 * @event deactivate
37113 * Fires when this panel is activated.
37114 * @param {Roo.ContentPanel} this
37116 "deactivate" : true,
37120 * Fires when this panel is resized if fitToFrame is true.
37121 * @param {Roo.ContentPanel} this
37122 * @param {Number} width The width after any component adjustments
37123 * @param {Number} height The height after any component adjustments
37129 * Fires when this tab is created
37130 * @param {Roo.ContentPanel} this
37141 if(this.autoScroll){
37142 this.resizeEl.setStyle("overflow", "auto");
37144 // fix randome scrolling
37145 //this.el.on('scroll', function() {
37146 // Roo.log('fix random scolling');
37147 // this.scrollTo('top',0);
37150 content = content || this.content;
37152 this.setContent(content);
37154 if(config && config.url){
37155 this.setUrl(this.url, this.params, this.loadOnce);
37160 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37162 if (this.view && typeof(this.view.xtype) != 'undefined') {
37163 this.view.el = this.el.appendChild(document.createElement("div"));
37164 this.view = Roo.factory(this.view);
37165 this.view.render && this.view.render(false, '');
37169 this.fireEvent('render', this);
37172 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37176 setRegion : function(region){
37177 this.region = region;
37178 this.setActiveClass(region && !this.background);
37182 setActiveClass: function(state)
37185 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37186 this.el.setStyle('position','relative');
37188 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37189 this.el.setStyle('position', 'absolute');
37194 * Returns the toolbar for this Panel if one was configured.
37195 * @return {Roo.Toolbar}
37197 getToolbar : function(){
37198 return this.toolbar;
37201 setActiveState : function(active)
37203 this.active = active;
37204 this.setActiveClass(active);
37206 if(this.fireEvent("deactivate", this) === false){
37211 this.fireEvent("activate", this);
37215 * Updates this panel's element
37216 * @param {String} content The new content
37217 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37219 setContent : function(content, loadScripts){
37220 this.el.update(content, loadScripts);
37223 ignoreResize : function(w, h){
37224 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37227 this.lastSize = {width: w, height: h};
37232 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37233 * @return {Roo.UpdateManager} The UpdateManager
37235 getUpdateManager : function(){
37236 return this.el.getUpdateManager();
37239 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37240 * @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:
37243 url: "your-url.php",
37244 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37245 callback: yourFunction,
37246 scope: yourObject, //(optional scope)
37249 text: "Loading...",
37254 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37255 * 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.
37256 * @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}
37257 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37258 * @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.
37259 * @return {Roo.ContentPanel} this
37262 var um = this.el.getUpdateManager();
37263 um.update.apply(um, arguments);
37269 * 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.
37270 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37271 * @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)
37272 * @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)
37273 * @return {Roo.UpdateManager} The UpdateManager
37275 setUrl : function(url, params, loadOnce){
37276 if(this.refreshDelegate){
37277 this.removeListener("activate", this.refreshDelegate);
37279 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37280 this.on("activate", this.refreshDelegate);
37281 return this.el.getUpdateManager();
37284 _handleRefresh : function(url, params, loadOnce){
37285 if(!loadOnce || !this.loaded){
37286 var updater = this.el.getUpdateManager();
37287 updater.update(url, params, this._setLoaded.createDelegate(this));
37291 _setLoaded : function(){
37292 this.loaded = true;
37296 * Returns this panel's id
37299 getId : function(){
37304 * Returns this panel's element - used by regiosn to add.
37305 * @return {Roo.Element}
37307 getEl : function(){
37308 return this.wrapEl || this.el;
37313 adjustForComponents : function(width, height)
37315 //Roo.log('adjustForComponents ');
37316 if(this.resizeEl != this.el){
37317 width -= this.el.getFrameWidth('lr');
37318 height -= this.el.getFrameWidth('tb');
37321 var te = this.toolbar.getEl();
37322 te.setWidth(width);
37323 height -= te.getHeight();
37326 var te = this.footer.getEl();
37327 te.setWidth(width);
37328 height -= te.getHeight();
37332 if(this.adjustments){
37333 width += this.adjustments[0];
37334 height += this.adjustments[1];
37336 return {"width": width, "height": height};
37339 setSize : function(width, height){
37340 if(this.fitToFrame && !this.ignoreResize(width, height)){
37341 if(this.fitContainer && this.resizeEl != this.el){
37342 this.el.setSize(width, height);
37344 var size = this.adjustForComponents(width, height);
37345 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37346 this.fireEvent('resize', this, size.width, size.height);
37351 * Returns this panel's title
37354 getTitle : function(){
37356 if (typeof(this.title) != 'object') {
37361 for (var k in this.title) {
37362 if (!this.title.hasOwnProperty(k)) {
37366 if (k.indexOf('-') >= 0) {
37367 var s = k.split('-');
37368 for (var i = 0; i<s.length; i++) {
37369 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37372 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37379 * Set this panel's title
37380 * @param {String} title
37382 setTitle : function(title){
37383 this.title = title;
37385 this.region.updatePanelTitle(this, title);
37390 * Returns true is this panel was configured to be closable
37391 * @return {Boolean}
37393 isClosable : function(){
37394 return this.closable;
37397 beforeSlide : function(){
37399 this.resizeEl.clip();
37402 afterSlide : function(){
37404 this.resizeEl.unclip();
37408 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37409 * Will fail silently if the {@link #setUrl} method has not been called.
37410 * This does not activate the panel, just updates its content.
37412 refresh : function(){
37413 if(this.refreshDelegate){
37414 this.loaded = false;
37415 this.refreshDelegate();
37420 * Destroys this panel
37422 destroy : function(){
37423 this.el.removeAllListeners();
37424 var tempEl = document.createElement("span");
37425 tempEl.appendChild(this.el.dom);
37426 tempEl.innerHTML = "";
37432 * form - if the content panel contains a form - this is a reference to it.
37433 * @type {Roo.form.Form}
37437 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37438 * This contains a reference to it.
37444 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37454 * @param {Object} cfg Xtype definition of item to add.
37458 getChildContainer: function () {
37459 return this.getEl();
37464 var ret = new Roo.factory(cfg);
37469 if (cfg.xtype.match(/^Form$/)) {
37472 //if (this.footer) {
37473 // el = this.footer.container.insertSibling(false, 'before');
37475 el = this.el.createChild();
37478 this.form = new Roo.form.Form(cfg);
37481 if ( this.form.allItems.length) {
37482 this.form.render(el.dom);
37486 // should only have one of theses..
37487 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37488 // views.. should not be just added - used named prop 'view''
37490 cfg.el = this.el.appendChild(document.createElement("div"));
37493 var ret = new Roo.factory(cfg);
37495 ret.render && ret.render(false, ''); // render blank..
37505 * @class Roo.bootstrap.panel.Grid
37506 * @extends Roo.bootstrap.panel.Content
37508 * Create a new GridPanel.
37509 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37510 * @param {Object} config A the config object
37516 Roo.bootstrap.panel.Grid = function(config)
37520 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37521 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37523 config.el = this.wrapper;
37524 //this.el = this.wrapper;
37526 if (config.container) {
37527 // ctor'ed from a Border/panel.grid
37530 this.wrapper.setStyle("overflow", "hidden");
37531 this.wrapper.addClass('roo-grid-container');
37536 if(config.toolbar){
37537 var tool_el = this.wrapper.createChild();
37538 this.toolbar = Roo.factory(config.toolbar);
37540 if (config.toolbar.items) {
37541 ti = config.toolbar.items ;
37542 delete config.toolbar.items ;
37546 this.toolbar.render(tool_el);
37547 for(var i =0;i < ti.length;i++) {
37548 // Roo.log(['add child', items[i]]);
37549 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37551 this.toolbar.items = nitems;
37553 delete config.toolbar;
37556 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37557 config.grid.scrollBody = true;;
37558 config.grid.monitorWindowResize = false; // turn off autosizing
37559 config.grid.autoHeight = false;
37560 config.grid.autoWidth = false;
37562 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37564 if (config.background) {
37565 // render grid on panel activation (if panel background)
37566 this.on('activate', function(gp) {
37567 if (!gp.grid.rendered) {
37568 gp.grid.render(this.wrapper);
37569 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37574 this.grid.render(this.wrapper);
37575 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37578 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37579 // ??? needed ??? config.el = this.wrapper;
37584 // xtype created footer. - not sure if will work as we normally have to render first..
37585 if (this.footer && !this.footer.el && this.footer.xtype) {
37587 var ctr = this.grid.getView().getFooterPanel(true);
37588 this.footer.dataSource = this.grid.dataSource;
37589 this.footer = Roo.factory(this.footer, Roo);
37590 this.footer.render(ctr);
37600 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37601 getId : function(){
37602 return this.grid.id;
37606 * Returns the grid for this panel
37607 * @return {Roo.bootstrap.Table}
37609 getGrid : function(){
37613 setSize : function(width, height){
37614 if(!this.ignoreResize(width, height)){
37615 var grid = this.grid;
37616 var size = this.adjustForComponents(width, height);
37617 var gridel = grid.getGridEl();
37618 gridel.setSize(size.width, size.height);
37620 var thd = grid.getGridEl().select('thead',true).first();
37621 var tbd = grid.getGridEl().select('tbody', true).first();
37623 tbd.setSize(width, height - thd.getHeight());
37632 beforeSlide : function(){
37633 this.grid.getView().scroller.clip();
37636 afterSlide : function(){
37637 this.grid.getView().scroller.unclip();
37640 destroy : function(){
37641 this.grid.destroy();
37643 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37648 * @class Roo.bootstrap.panel.Nest
37649 * @extends Roo.bootstrap.panel.Content
37651 * Create a new Panel, that can contain a layout.Border.
37654 * @param {Roo.BorderLayout} layout The layout for this panel
37655 * @param {String/Object} config A string to set only the title or a config object
37657 Roo.bootstrap.panel.Nest = function(config)
37659 // construct with only one argument..
37660 /* FIXME - implement nicer consturctors
37661 if (layout.layout) {
37663 layout = config.layout;
37664 delete config.layout;
37666 if (layout.xtype && !layout.getEl) {
37667 // then layout needs constructing..
37668 layout = Roo.factory(layout, Roo);
37672 config.el = config.layout.getEl();
37674 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37676 config.layout.monitorWindowResize = false; // turn off autosizing
37677 this.layout = config.layout;
37678 this.layout.getEl().addClass("roo-layout-nested-layout");
37685 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37687 setSize : function(width, height){
37688 if(!this.ignoreResize(width, height)){
37689 var size = this.adjustForComponents(width, height);
37690 var el = this.layout.getEl();
37691 if (size.height < 1) {
37692 el.setWidth(size.width);
37694 el.setSize(size.width, size.height);
37696 var touch = el.dom.offsetWidth;
37697 this.layout.layout();
37698 // ie requires a double layout on the first pass
37699 if(Roo.isIE && !this.initialized){
37700 this.initialized = true;
37701 this.layout.layout();
37706 // activate all subpanels if not currently active..
37708 setActiveState : function(active){
37709 this.active = active;
37710 this.setActiveClass(active);
37713 this.fireEvent("deactivate", this);
37717 this.fireEvent("activate", this);
37718 // not sure if this should happen before or after..
37719 if (!this.layout) {
37720 return; // should not happen..
37723 for (var r in this.layout.regions) {
37724 reg = this.layout.getRegion(r);
37725 if (reg.getActivePanel()) {
37726 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37727 reg.setActivePanel(reg.getActivePanel());
37730 if (!reg.panels.length) {
37733 reg.showPanel(reg.getPanel(0));
37742 * Returns the nested BorderLayout for this panel
37743 * @return {Roo.BorderLayout}
37745 getLayout : function(){
37746 return this.layout;
37750 * Adds a xtype elements to the layout of the nested panel
37754 xtype : 'ContentPanel',
37761 xtype : 'NestedLayoutPanel',
37767 items : [ ... list of content panels or nested layout panels.. ]
37771 * @param {Object} cfg Xtype definition of item to add.
37773 addxtype : function(cfg) {
37774 return this.layout.addxtype(cfg);
37779 * Ext JS Library 1.1.1
37780 * Copyright(c) 2006-2007, Ext JS, LLC.
37782 * Originally Released Under LGPL - original licence link has changed is not relivant.
37785 * <script type="text/javascript">
37788 * @class Roo.TabPanel
37789 * @extends Roo.util.Observable
37790 * A lightweight tab container.
37794 // basic tabs 1, built from existing content
37795 var tabs = new Roo.TabPanel("tabs1");
37796 tabs.addTab("script", "View Script");
37797 tabs.addTab("markup", "View Markup");
37798 tabs.activate("script");
37800 // more advanced tabs, built from javascript
37801 var jtabs = new Roo.TabPanel("jtabs");
37802 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37804 // set up the UpdateManager
37805 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37806 var updater = tab2.getUpdateManager();
37807 updater.setDefaultUrl("ajax1.htm");
37808 tab2.on('activate', updater.refresh, updater, true);
37810 // Use setUrl for Ajax loading
37811 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37812 tab3.setUrl("ajax2.htm", null, true);
37815 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37818 jtabs.activate("jtabs-1");
37821 * Create a new TabPanel.
37822 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37823 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37825 Roo.bootstrap.panel.Tabs = function(config){
37827 * The container element for this TabPanel.
37828 * @type Roo.Element
37830 this.el = Roo.get(config.el);
37833 if(typeof config == "boolean"){
37834 this.tabPosition = config ? "bottom" : "top";
37836 Roo.apply(this, config);
37840 if(this.tabPosition == "bottom"){
37841 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37842 this.el.addClass("roo-tabs-bottom");
37844 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37845 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37846 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37848 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37850 if(this.tabPosition != "bottom"){
37851 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37852 * @type Roo.Element
37854 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37855 this.el.addClass("roo-tabs-top");
37859 this.bodyEl.setStyle("position", "relative");
37861 this.active = null;
37862 this.activateDelegate = this.activate.createDelegate(this);
37867 * Fires when the active tab changes
37868 * @param {Roo.TabPanel} this
37869 * @param {Roo.TabPanelItem} activePanel The new active tab
37873 * @event beforetabchange
37874 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37875 * @param {Roo.TabPanel} this
37876 * @param {Object} e Set cancel to true on this object to cancel the tab change
37877 * @param {Roo.TabPanelItem} tab The tab being changed to
37879 "beforetabchange" : true
37882 Roo.EventManager.onWindowResize(this.onResize, this);
37883 this.cpad = this.el.getPadding("lr");
37884 this.hiddenCount = 0;
37887 // toolbar on the tabbar support...
37888 if (this.toolbar) {
37889 alert("no toolbar support yet");
37890 this.toolbar = false;
37892 var tcfg = this.toolbar;
37893 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37894 this.toolbar = new Roo.Toolbar(tcfg);
37895 if (Roo.isSafari) {
37896 var tbl = tcfg.container.child('table', true);
37897 tbl.setAttribute('width', '100%');
37905 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37908 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37910 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37912 tabPosition : "top",
37914 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37916 currentTabWidth : 0,
37918 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37922 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37926 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37928 preferredTabWidth : 175,
37930 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37932 resizeTabs : false,
37934 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37936 monitorResize : true,
37938 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37943 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37944 * @param {String} id The id of the div to use <b>or create</b>
37945 * @param {String} text The text for the tab
37946 * @param {String} content (optional) Content to put in the TabPanelItem body
37947 * @param {Boolean} closable (optional) True to create a close icon on the tab
37948 * @return {Roo.TabPanelItem} The created TabPanelItem
37950 addTab : function(id, text, content, closable, tpl)
37952 var item = new Roo.bootstrap.panel.TabItem({
37956 closable : closable,
37959 this.addTabItem(item);
37961 item.setContent(content);
37967 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37968 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37969 * @return {Roo.TabPanelItem}
37971 getTab : function(id){
37972 return this.items[id];
37976 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37977 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37979 hideTab : function(id){
37980 var t = this.items[id];
37983 this.hiddenCount++;
37984 this.autoSizeTabs();
37989 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37990 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37992 unhideTab : function(id){
37993 var t = this.items[id];
37995 t.setHidden(false);
37996 this.hiddenCount--;
37997 this.autoSizeTabs();
38002 * Adds an existing {@link Roo.TabPanelItem}.
38003 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38005 addTabItem : function(item){
38006 this.items[item.id] = item;
38007 this.items.push(item);
38008 // if(this.resizeTabs){
38009 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38010 // this.autoSizeTabs();
38012 // item.autoSize();
38017 * Removes a {@link Roo.TabPanelItem}.
38018 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38020 removeTab : function(id){
38021 var items = this.items;
38022 var tab = items[id];
38023 if(!tab) { return; }
38024 var index = items.indexOf(tab);
38025 if(this.active == tab && items.length > 1){
38026 var newTab = this.getNextAvailable(index);
38031 this.stripEl.dom.removeChild(tab.pnode.dom);
38032 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38033 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38035 items.splice(index, 1);
38036 delete this.items[tab.id];
38037 tab.fireEvent("close", tab);
38038 tab.purgeListeners();
38039 this.autoSizeTabs();
38042 getNextAvailable : function(start){
38043 var items = this.items;
38045 // look for a next tab that will slide over to
38046 // replace the one being removed
38047 while(index < items.length){
38048 var item = items[++index];
38049 if(item && !item.isHidden()){
38053 // if one isn't found select the previous tab (on the left)
38056 var item = items[--index];
38057 if(item && !item.isHidden()){
38065 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38066 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38068 disableTab : function(id){
38069 var tab = this.items[id];
38070 if(tab && this.active != tab){
38076 * Enables a {@link Roo.TabPanelItem} that is disabled.
38077 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38079 enableTab : function(id){
38080 var tab = this.items[id];
38085 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38086 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38087 * @return {Roo.TabPanelItem} The TabPanelItem.
38089 activate : function(id){
38090 var tab = this.items[id];
38094 if(tab == this.active || tab.disabled){
38098 this.fireEvent("beforetabchange", this, e, tab);
38099 if(e.cancel !== true && !tab.disabled){
38101 this.active.hide();
38103 this.active = this.items[id];
38104 this.active.show();
38105 this.fireEvent("tabchange", this, this.active);
38111 * Gets the active {@link Roo.TabPanelItem}.
38112 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38114 getActiveTab : function(){
38115 return this.active;
38119 * Updates the tab body element to fit the height of the container element
38120 * for overflow scrolling
38121 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38123 syncHeight : function(targetHeight){
38124 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38125 var bm = this.bodyEl.getMargins();
38126 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38127 this.bodyEl.setHeight(newHeight);
38131 onResize : function(){
38132 if(this.monitorResize){
38133 this.autoSizeTabs();
38138 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38140 beginUpdate : function(){
38141 this.updating = true;
38145 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38147 endUpdate : function(){
38148 this.updating = false;
38149 this.autoSizeTabs();
38153 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38155 autoSizeTabs : function(){
38156 var count = this.items.length;
38157 var vcount = count - this.hiddenCount;
38158 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38161 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38162 var availWidth = Math.floor(w / vcount);
38163 var b = this.stripBody;
38164 if(b.getWidth() > w){
38165 var tabs = this.items;
38166 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38167 if(availWidth < this.minTabWidth){
38168 /*if(!this.sleft){ // incomplete scrolling code
38169 this.createScrollButtons();
38172 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38175 if(this.currentTabWidth < this.preferredTabWidth){
38176 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38182 * Returns the number of tabs in this TabPanel.
38185 getCount : function(){
38186 return this.items.length;
38190 * Resizes all the tabs to the passed width
38191 * @param {Number} The new width
38193 setTabWidth : function(width){
38194 this.currentTabWidth = width;
38195 for(var i = 0, len = this.items.length; i < len; i++) {
38196 if(!this.items[i].isHidden()) {
38197 this.items[i].setWidth(width);
38203 * Destroys this TabPanel
38204 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38206 destroy : function(removeEl){
38207 Roo.EventManager.removeResizeListener(this.onResize, this);
38208 for(var i = 0, len = this.items.length; i < len; i++){
38209 this.items[i].purgeListeners();
38211 if(removeEl === true){
38212 this.el.update("");
38217 createStrip : function(container)
38219 var strip = document.createElement("nav");
38220 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38221 container.appendChild(strip);
38225 createStripList : function(strip)
38227 // div wrapper for retard IE
38228 // returns the "tr" element.
38229 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38230 //'<div class="x-tabs-strip-wrap">'+
38231 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38232 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38233 return strip.firstChild; //.firstChild.firstChild.firstChild;
38235 createBody : function(container)
38237 var body = document.createElement("div");
38238 Roo.id(body, "tab-body");
38239 //Roo.fly(body).addClass("x-tabs-body");
38240 Roo.fly(body).addClass("tab-content");
38241 container.appendChild(body);
38244 createItemBody :function(bodyEl, id){
38245 var body = Roo.getDom(id);
38247 body = document.createElement("div");
38250 //Roo.fly(body).addClass("x-tabs-item-body");
38251 Roo.fly(body).addClass("tab-pane");
38252 bodyEl.insertBefore(body, bodyEl.firstChild);
38256 createStripElements : function(stripEl, text, closable, tpl)
38258 var td = document.createElement("li"); // was td..
38261 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38264 stripEl.appendChild(td);
38266 td.className = "x-tabs-closable";
38267 if(!this.closeTpl){
38268 this.closeTpl = new Roo.Template(
38269 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38270 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38271 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38274 var el = this.closeTpl.overwrite(td, {"text": text});
38275 var close = el.getElementsByTagName("div")[0];
38276 var inner = el.getElementsByTagName("em")[0];
38277 return {"el": el, "close": close, "inner": inner};
38280 // not sure what this is..
38281 // if(!this.tabTpl){
38282 //this.tabTpl = new Roo.Template(
38283 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38284 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38286 // this.tabTpl = new Roo.Template(
38287 // '<a href="#">' +
38288 // '<span unselectable="on"' +
38289 // (this.disableTooltips ? '' : ' title="{text}"') +
38290 // ' >{text}</span></a>'
38296 var template = tpl || this.tabTpl || false;
38300 template = new Roo.Template(
38302 '<span unselectable="on"' +
38303 (this.disableTooltips ? '' : ' title="{text}"') +
38304 ' >{text}</span></a>'
38308 switch (typeof(template)) {
38312 template = new Roo.Template(template);
38318 var el = template.overwrite(td, {"text": text});
38320 var inner = el.getElementsByTagName("span")[0];
38322 return {"el": el, "inner": inner};
38330 * @class Roo.TabPanelItem
38331 * @extends Roo.util.Observable
38332 * Represents an individual item (tab plus body) in a TabPanel.
38333 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38334 * @param {String} id The id of this TabPanelItem
38335 * @param {String} text The text for the tab of this TabPanelItem
38336 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38338 Roo.bootstrap.panel.TabItem = function(config){
38340 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38341 * @type Roo.TabPanel
38343 this.tabPanel = config.panel;
38345 * The id for this TabPanelItem
38348 this.id = config.id;
38350 this.disabled = false;
38352 this.text = config.text;
38354 this.loaded = false;
38355 this.closable = config.closable;
38358 * The body element for this TabPanelItem.
38359 * @type Roo.Element
38361 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38362 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38363 this.bodyEl.setStyle("display", "block");
38364 this.bodyEl.setStyle("zoom", "1");
38365 //this.hideAction();
38367 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38369 this.el = Roo.get(els.el);
38370 this.inner = Roo.get(els.inner, true);
38371 this.textEl = Roo.get(this.el.dom.firstChild, true);
38372 this.pnode = Roo.get(els.el.parentNode, true);
38373 // this.el.on("mousedown", this.onTabMouseDown, this);
38374 this.el.on("click", this.onTabClick, this);
38376 if(config.closable){
38377 var c = Roo.get(els.close, true);
38378 c.dom.title = this.closeText;
38379 c.addClassOnOver("close-over");
38380 c.on("click", this.closeClick, this);
38386 * Fires when this tab becomes the active tab.
38387 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38388 * @param {Roo.TabPanelItem} this
38392 * @event beforeclose
38393 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38394 * @param {Roo.TabPanelItem} this
38395 * @param {Object} e Set cancel to true on this object to cancel the close.
38397 "beforeclose": true,
38400 * Fires when this tab is closed.
38401 * @param {Roo.TabPanelItem} this
38405 * @event deactivate
38406 * Fires when this tab is no longer the active tab.
38407 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38408 * @param {Roo.TabPanelItem} this
38410 "deactivate" : true
38412 this.hidden = false;
38414 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38417 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38419 purgeListeners : function(){
38420 Roo.util.Observable.prototype.purgeListeners.call(this);
38421 this.el.removeAllListeners();
38424 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38427 this.pnode.addClass("active");
38430 this.tabPanel.stripWrap.repaint();
38432 this.fireEvent("activate", this.tabPanel, this);
38436 * Returns true if this tab is the active tab.
38437 * @return {Boolean}
38439 isActive : function(){
38440 return this.tabPanel.getActiveTab() == this;
38444 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38447 this.pnode.removeClass("active");
38449 this.fireEvent("deactivate", this.tabPanel, this);
38452 hideAction : function(){
38453 this.bodyEl.hide();
38454 this.bodyEl.setStyle("position", "absolute");
38455 this.bodyEl.setLeft("-20000px");
38456 this.bodyEl.setTop("-20000px");
38459 showAction : function(){
38460 this.bodyEl.setStyle("position", "relative");
38461 this.bodyEl.setTop("");
38462 this.bodyEl.setLeft("");
38463 this.bodyEl.show();
38467 * Set the tooltip for the tab.
38468 * @param {String} tooltip The tab's tooltip
38470 setTooltip : function(text){
38471 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38472 this.textEl.dom.qtip = text;
38473 this.textEl.dom.removeAttribute('title');
38475 this.textEl.dom.title = text;
38479 onTabClick : function(e){
38480 e.preventDefault();
38481 this.tabPanel.activate(this.id);
38484 onTabMouseDown : function(e){
38485 e.preventDefault();
38486 this.tabPanel.activate(this.id);
38489 getWidth : function(){
38490 return this.inner.getWidth();
38493 setWidth : function(width){
38494 var iwidth = width - this.pnode.getPadding("lr");
38495 this.inner.setWidth(iwidth);
38496 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38497 this.pnode.setWidth(width);
38501 * Show or hide the tab
38502 * @param {Boolean} hidden True to hide or false to show.
38504 setHidden : function(hidden){
38505 this.hidden = hidden;
38506 this.pnode.setStyle("display", hidden ? "none" : "");
38510 * Returns true if this tab is "hidden"
38511 * @return {Boolean}
38513 isHidden : function(){
38514 return this.hidden;
38518 * Returns the text for this tab
38521 getText : function(){
38525 autoSize : function(){
38526 //this.el.beginMeasure();
38527 this.textEl.setWidth(1);
38529 * #2804 [new] Tabs in Roojs
38530 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38532 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38533 //this.el.endMeasure();
38537 * Sets the text for the tab (Note: this also sets the tooltip text)
38538 * @param {String} text The tab's text and tooltip
38540 setText : function(text){
38542 this.textEl.update(text);
38543 this.setTooltip(text);
38544 //if(!this.tabPanel.resizeTabs){
38545 // this.autoSize();
38549 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38551 activate : function(){
38552 this.tabPanel.activate(this.id);
38556 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38558 disable : function(){
38559 if(this.tabPanel.active != this){
38560 this.disabled = true;
38561 this.pnode.addClass("disabled");
38566 * Enables this TabPanelItem if it was previously disabled.
38568 enable : function(){
38569 this.disabled = false;
38570 this.pnode.removeClass("disabled");
38574 * Sets the content for this TabPanelItem.
38575 * @param {String} content The content
38576 * @param {Boolean} loadScripts true to look for and load scripts
38578 setContent : function(content, loadScripts){
38579 this.bodyEl.update(content, loadScripts);
38583 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38584 * @return {Roo.UpdateManager} The UpdateManager
38586 getUpdateManager : function(){
38587 return this.bodyEl.getUpdateManager();
38591 * Set a URL to be used to load the content for this TabPanelItem.
38592 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38593 * @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)
38594 * @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)
38595 * @return {Roo.UpdateManager} The UpdateManager
38597 setUrl : function(url, params, loadOnce){
38598 if(this.refreshDelegate){
38599 this.un('activate', this.refreshDelegate);
38601 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38602 this.on("activate", this.refreshDelegate);
38603 return this.bodyEl.getUpdateManager();
38607 _handleRefresh : function(url, params, loadOnce){
38608 if(!loadOnce || !this.loaded){
38609 var updater = this.bodyEl.getUpdateManager();
38610 updater.update(url, params, this._setLoaded.createDelegate(this));
38615 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38616 * Will fail silently if the setUrl method has not been called.
38617 * This does not activate the panel, just updates its content.
38619 refresh : function(){
38620 if(this.refreshDelegate){
38621 this.loaded = false;
38622 this.refreshDelegate();
38627 _setLoaded : function(){
38628 this.loaded = true;
38632 closeClick : function(e){
38635 this.fireEvent("beforeclose", this, o);
38636 if(o.cancel !== true){
38637 this.tabPanel.removeTab(this.id);
38641 * The text displayed in the tooltip for the close icon.
38644 closeText : "Close this tab"
38647 * This script refer to:
38648 * Title: International Telephone Input
38649 * Author: Jack O'Connor
38650 * Code version: v12.1.12
38651 * Availability: https://github.com/jackocnr/intl-tel-input.git
38654 Roo.bootstrap.PhoneInputData = function() {
38657 "Afghanistan (افغانستان)",
38662 "Albania (Shqipëri)",
38667 "Algeria (الجزائر)",
38692 "Antigua and Barbuda",
38702 "Armenia (Հայաստան)",
38718 "Austria (Österreich)",
38723 "Azerbaijan (Azərbaycan)",
38733 "Bahrain (البحرين)",
38738 "Bangladesh (বাংলাদেশ)",
38748 "Belarus (Беларусь)",
38753 "Belgium (België)",
38783 "Bosnia and Herzegovina (Босна и Херцеговина)",
38798 "British Indian Ocean Territory",
38803 "British Virgin Islands",
38813 "Bulgaria (България)",
38823 "Burundi (Uburundi)",
38828 "Cambodia (កម្ពុជា)",
38833 "Cameroon (Cameroun)",
38842 ["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"]
38845 "Cape Verde (Kabu Verdi)",
38850 "Caribbean Netherlands",
38861 "Central African Republic (République centrafricaine)",
38881 "Christmas Island",
38887 "Cocos (Keeling) Islands",
38898 "Comoros (جزر القمر)",
38903 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38908 "Congo (Republic) (Congo-Brazzaville)",
38928 "Croatia (Hrvatska)",
38949 "Czech Republic (Česká republika)",
38954 "Denmark (Danmark)",
38969 "Dominican Republic (República Dominicana)",
38973 ["809", "829", "849"]
38991 "Equatorial Guinea (Guinea Ecuatorial)",
39011 "Falkland Islands (Islas Malvinas)",
39016 "Faroe Islands (Føroyar)",
39037 "French Guiana (Guyane française)",
39042 "French Polynesia (Polynésie française)",
39057 "Georgia (საქართველო)",
39062 "Germany (Deutschland)",
39082 "Greenland (Kalaallit Nunaat)",
39119 "Guinea-Bissau (Guiné Bissau)",
39144 "Hungary (Magyarország)",
39149 "Iceland (Ísland)",
39169 "Iraq (العراق)",
39185 "Israel (ישראל)",
39212 "Jordan (الأردن)",
39217 "Kazakhstan (Казахстан)",
39238 "Kuwait (الكويت)",
39243 "Kyrgyzstan (Кыргызстан)",
39253 "Latvia (Latvija)",
39258 "Lebanon (لبنان)",
39273 "Libya (ليبيا)",
39283 "Lithuania (Lietuva)",
39298 "Macedonia (FYROM) (Македонија)",
39303 "Madagascar (Madagasikara)",
39333 "Marshall Islands",
39343 "Mauritania (موريتانيا)",
39348 "Mauritius (Moris)",
39369 "Moldova (Republica Moldova)",
39379 "Mongolia (Монгол)",
39384 "Montenegro (Crna Gora)",
39394 "Morocco (المغرب)",
39400 "Mozambique (Moçambique)",
39405 "Myanmar (Burma) (မြန်မာ)",
39410 "Namibia (Namibië)",
39425 "Netherlands (Nederland)",
39430 "New Caledonia (Nouvelle-Calédonie)",
39465 "North Korea (조선 민주주의 인민 공화국)",
39470 "Northern Mariana Islands",
39486 "Pakistan (پاکستان)",
39496 "Palestine (فلسطين)",
39506 "Papua New Guinea",
39548 "Réunion (La Réunion)",
39554 "Romania (România)",
39570 "Saint Barthélemy",
39581 "Saint Kitts and Nevis",
39591 "Saint Martin (Saint-Martin (partie française))",
39597 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39602 "Saint Vincent and the Grenadines",
39617 "São Tomé and Príncipe (São Tomé e Príncipe)",
39622 "Saudi Arabia (المملكة العربية السعودية)",
39627 "Senegal (Sénégal)",
39657 "Slovakia (Slovensko)",
39662 "Slovenia (Slovenija)",
39672 "Somalia (Soomaaliya)",
39682 "South Korea (대한민국)",
39687 "South Sudan (جنوب السودان)",
39697 "Sri Lanka (ශ්රී ලංකාව)",
39702 "Sudan (السودان)",
39712 "Svalbard and Jan Mayen",
39723 "Sweden (Sverige)",
39728 "Switzerland (Schweiz)",
39733 "Syria (سوريا)",
39778 "Trinidad and Tobago",
39783 "Tunisia (تونس)",
39788 "Turkey (Türkiye)",
39798 "Turks and Caicos Islands",
39808 "U.S. Virgin Islands",
39818 "Ukraine (Україна)",
39823 "United Arab Emirates (الإمارات العربية المتحدة)",
39845 "Uzbekistan (Oʻzbekiston)",
39855 "Vatican City (Città del Vaticano)",
39866 "Vietnam (Việt Nam)",
39871 "Wallis and Futuna (Wallis-et-Futuna)",
39876 "Western Sahara (الصحراء الغربية)",
39882 "Yemen (اليمن)",
39906 * This script refer to:
39907 * Title: International Telephone Input
39908 * Author: Jack O'Connor
39909 * Code version: v12.1.12
39910 * Availability: https://github.com/jackocnr/intl-tel-input.git
39914 * @class Roo.bootstrap.PhoneInput
39915 * @extends Roo.bootstrap.TriggerField
39916 * An input with International dial-code selection
39918 * @cfg {String} defaultDialCode default '+852'
39919 * @cfg {Array} preferedCountries default []
39922 * Create a new PhoneInput.
39923 * @param {Object} config Configuration options
39926 Roo.bootstrap.PhoneInput = function(config) {
39927 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39930 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39932 listWidth: undefined,
39934 selectedClass: 'active',
39936 invalidClass : "has-warning",
39938 validClass: 'has-success',
39940 allowed: '0123456789',
39945 * @cfg {String} defaultDialCode The default dial code when initializing the input
39947 defaultDialCode: '+852',
39950 * @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
39952 preferedCountries: false,
39954 getAutoCreate : function()
39956 var data = Roo.bootstrap.PhoneInputData();
39957 var align = this.labelAlign || this.parentLabelAlign();
39960 this.allCountries = [];
39961 this.dialCodeMapping = [];
39963 for (var i = 0; i < data.length; i++) {
39965 this.allCountries[i] = {
39969 priority: c[3] || 0,
39970 areaCodes: c[4] || null
39972 this.dialCodeMapping[c[2]] = {
39975 priority: c[3] || 0,
39976 areaCodes: c[4] || null
39988 // type: 'number', -- do not use number - we get the flaky up/down arrows.
39989 maxlength: this.max_length,
39990 cls : 'form-control tel-input',
39991 autocomplete: 'new-password'
39994 var hiddenInput = {
39997 cls: 'hidden-tel-input'
40001 hiddenInput.name = this.name;
40004 if (this.disabled) {
40005 input.disabled = true;
40008 var flag_container = {
40025 cls: this.hasFeedback ? 'has-feedback' : '',
40031 cls: 'dial-code-holder',
40038 cls: 'roo-select2-container input-group',
40045 if (this.fieldLabel.length) {
40048 tooltip: 'This field is required'
40054 cls: 'control-label',
40060 html: this.fieldLabel
40063 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40069 if(this.indicatorpos == 'right') {
40070 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40077 if(align == 'left') {
40085 if(this.labelWidth > 12){
40086 label.style = "width: " + this.labelWidth + 'px';
40088 if(this.labelWidth < 13 && this.labelmd == 0){
40089 this.labelmd = this.labelWidth;
40091 if(this.labellg > 0){
40092 label.cls += ' col-lg-' + this.labellg;
40093 input.cls += ' col-lg-' + (12 - this.labellg);
40095 if(this.labelmd > 0){
40096 label.cls += ' col-md-' + this.labelmd;
40097 container.cls += ' col-md-' + (12 - this.labelmd);
40099 if(this.labelsm > 0){
40100 label.cls += ' col-sm-' + this.labelsm;
40101 container.cls += ' col-sm-' + (12 - this.labelsm);
40103 if(this.labelxs > 0){
40104 label.cls += ' col-xs-' + this.labelxs;
40105 container.cls += ' col-xs-' + (12 - this.labelxs);
40115 var settings = this;
40117 ['xs','sm','md','lg'].map(function(size){
40118 if (settings[size]) {
40119 cfg.cls += ' col-' + size + '-' + settings[size];
40123 this.store = new Roo.data.Store({
40124 proxy : new Roo.data.MemoryProxy({}),
40125 reader : new Roo.data.JsonReader({
40136 'name' : 'dialCode',
40140 'name' : 'priority',
40144 'name' : 'areaCodes',
40151 if(!this.preferedCountries) {
40152 this.preferedCountries = [
40159 var p = this.preferedCountries.reverse();
40162 for (var i = 0; i < p.length; i++) {
40163 for (var j = 0; j < this.allCountries.length; j++) {
40164 if(this.allCountries[j].iso2 == p[i]) {
40165 var t = this.allCountries[j];
40166 this.allCountries.splice(j,1);
40167 this.allCountries.unshift(t);
40173 this.store.proxy.data = {
40175 data: this.allCountries
40181 initEvents : function()
40184 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40186 this.indicator = this.indicatorEl();
40187 this.flag = this.flagEl();
40188 this.dialCodeHolder = this.dialCodeHolderEl();
40190 this.trigger = this.el.select('div.flag-box',true).first();
40191 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40196 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40197 _this.list.setWidth(lw);
40200 this.list.on('mouseover', this.onViewOver, this);
40201 this.list.on('mousemove', this.onViewMove, this);
40202 this.inputEl().on("keyup", this.onKeyUp, this);
40203 this.inputEl().on("keypress", this.onKeyPress, this);
40205 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40207 this.view = new Roo.View(this.list, this.tpl, {
40208 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40211 this.view.on('click', this.onViewClick, this);
40212 this.setValue(this.defaultDialCode);
40215 onTriggerClick : function(e)
40217 Roo.log('trigger click');
40222 if(this.isExpanded()){
40224 this.hasFocus = false;
40226 this.store.load({});
40227 this.hasFocus = true;
40232 isExpanded : function()
40234 return this.list.isVisible();
40237 collapse : function()
40239 if(!this.isExpanded()){
40243 Roo.get(document).un('mousedown', this.collapseIf, this);
40244 Roo.get(document).un('mousewheel', this.collapseIf, this);
40245 this.fireEvent('collapse', this);
40249 expand : function()
40253 if(this.isExpanded() || !this.hasFocus){
40257 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40258 this.list.setWidth(lw);
40261 this.restrictHeight();
40263 Roo.get(document).on('mousedown', this.collapseIf, this);
40264 Roo.get(document).on('mousewheel', this.collapseIf, this);
40266 this.fireEvent('expand', this);
40269 restrictHeight : function()
40271 this.list.alignTo(this.inputEl(), this.listAlign);
40272 this.list.alignTo(this.inputEl(), this.listAlign);
40275 onViewOver : function(e, t)
40277 if(this.inKeyMode){
40280 var item = this.view.findItemFromChild(t);
40283 var index = this.view.indexOf(item);
40284 this.select(index, false);
40289 onViewClick : function(view, doFocus, el, e)
40291 var index = this.view.getSelectedIndexes()[0];
40293 var r = this.store.getAt(index);
40296 this.onSelect(r, index);
40298 if(doFocus !== false && !this.blockFocus){
40299 this.inputEl().focus();
40303 onViewMove : function(e, t)
40305 this.inKeyMode = false;
40308 select : function(index, scrollIntoView)
40310 this.selectedIndex = index;
40311 this.view.select(index);
40312 if(scrollIntoView !== false){
40313 var el = this.view.getNode(index);
40315 this.list.scrollChildIntoView(el, false);
40320 createList : function()
40322 this.list = Roo.get(document.body).createChild({
40324 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40325 style: 'display:none'
40328 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40331 collapseIf : function(e)
40333 var in_combo = e.within(this.el);
40334 var in_list = e.within(this.list);
40335 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40337 if (in_combo || in_list || is_list) {
40343 onSelect : function(record, index)
40345 if(this.fireEvent('beforeselect', this, record, index) !== false){
40347 this.setFlagClass(record.data.iso2);
40348 this.setDialCode(record.data.dialCode);
40349 this.hasFocus = false;
40351 this.fireEvent('select', this, record, index);
40355 flagEl : function()
40357 var flag = this.el.select('div.flag',true).first();
40364 dialCodeHolderEl : function()
40366 var d = this.el.select('input.dial-code-holder',true).first();
40373 setDialCode : function(v)
40375 this.dialCodeHolder.dom.value = '+'+v;
40378 setFlagClass : function(n)
40380 this.flag.dom.className = 'flag '+n;
40383 getValue : function()
40385 var v = this.inputEl().getValue();
40386 if(this.dialCodeHolder) {
40387 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40392 setValue : function(v)
40394 var d = this.getDialCode(v);
40396 //invalid dial code
40397 if(v.length == 0 || !d || d.length == 0) {
40399 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40400 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40406 this.setFlagClass(this.dialCodeMapping[d].iso2);
40407 this.setDialCode(d);
40408 this.inputEl().dom.value = v.replace('+'+d,'');
40409 this.hiddenEl().dom.value = this.getValue();
40414 getDialCode : function(v)
40418 if (v.length == 0) {
40419 return this.dialCodeHolder.dom.value;
40423 if (v.charAt(0) != "+") {
40426 var numericChars = "";
40427 for (var i = 1; i < v.length; i++) {
40428 var c = v.charAt(i);
40431 if (this.dialCodeMapping[numericChars]) {
40432 dialCode = v.substr(1, i);
40434 if (numericChars.length == 4) {
40444 this.setValue(this.defaultDialCode);
40448 hiddenEl : function()
40450 return this.el.select('input.hidden-tel-input',true).first();
40453 // after setting val
40454 onKeyUp : function(e){
40455 this.setValue(this.getValue());
40458 onKeyPress : function(e){
40459 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40466 * @class Roo.bootstrap.MoneyField
40467 * @extends Roo.bootstrap.ComboBox
40468 * Bootstrap MoneyField class
40471 * Create a new MoneyField.
40472 * @param {Object} config Configuration options
40475 Roo.bootstrap.MoneyField = function(config) {
40477 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40481 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40484 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40486 allowDecimals : true,
40488 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40490 decimalSeparator : ".",
40492 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40494 decimalPrecision : 0,
40496 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40498 allowNegative : true,
40500 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40504 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40506 minValue : Number.NEGATIVE_INFINITY,
40508 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40510 maxValue : Number.MAX_VALUE,
40512 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40514 minText : "The minimum value for this field is {0}",
40516 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40518 maxText : "The maximum value for this field is {0}",
40520 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40521 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40523 nanText : "{0} is not a valid number",
40525 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40529 * @cfg {String} defaults currency of the MoneyField
40530 * value should be in lkey
40532 defaultCurrency : false,
40534 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40536 thousandsDelimiter : false,
40538 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40549 getAutoCreate : function()
40551 var align = this.labelAlign || this.parentLabelAlign();
40563 cls : 'form-control roo-money-amount-input',
40564 autocomplete: 'new-password'
40567 var hiddenInput = {
40571 cls: 'hidden-number-input'
40574 if(this.max_length) {
40575 input.maxlength = this.max_length;
40579 hiddenInput.name = this.name;
40582 if (this.disabled) {
40583 input.disabled = true;
40586 var clg = 12 - this.inputlg;
40587 var cmd = 12 - this.inputmd;
40588 var csm = 12 - this.inputsm;
40589 var cxs = 12 - this.inputxs;
40593 cls : 'row roo-money-field',
40597 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40601 cls: 'roo-select2-container input-group',
40605 cls : 'form-control roo-money-currency-input',
40606 autocomplete: 'new-password',
40608 name : this.currencyName
40612 cls : 'input-group-addon',
40626 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40630 cls: this.hasFeedback ? 'has-feedback' : '',
40641 if (this.fieldLabel.length) {
40644 tooltip: 'This field is required'
40650 cls: 'control-label',
40656 html: this.fieldLabel
40659 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40665 if(this.indicatorpos == 'right') {
40666 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40673 if(align == 'left') {
40681 if(this.labelWidth > 12){
40682 label.style = "width: " + this.labelWidth + 'px';
40684 if(this.labelWidth < 13 && this.labelmd == 0){
40685 this.labelmd = this.labelWidth;
40687 if(this.labellg > 0){
40688 label.cls += ' col-lg-' + this.labellg;
40689 input.cls += ' col-lg-' + (12 - this.labellg);
40691 if(this.labelmd > 0){
40692 label.cls += ' col-md-' + this.labelmd;
40693 container.cls += ' col-md-' + (12 - this.labelmd);
40695 if(this.labelsm > 0){
40696 label.cls += ' col-sm-' + this.labelsm;
40697 container.cls += ' col-sm-' + (12 - this.labelsm);
40699 if(this.labelxs > 0){
40700 label.cls += ' col-xs-' + this.labelxs;
40701 container.cls += ' col-xs-' + (12 - this.labelxs);
40712 var settings = this;
40714 ['xs','sm','md','lg'].map(function(size){
40715 if (settings[size]) {
40716 cfg.cls += ' col-' + size + '-' + settings[size];
40723 initEvents : function()
40725 this.indicator = this.indicatorEl();
40727 this.initCurrencyEvent();
40729 this.initNumberEvent();
40732 initCurrencyEvent : function()
40735 throw "can not find store for combo";
40738 this.store = Roo.factory(this.store, Roo.data);
40739 this.store.parent = this;
40743 this.triggerEl = this.el.select('.input-group-addon', true).first();
40745 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40750 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40751 _this.list.setWidth(lw);
40754 this.list.on('mouseover', this.onViewOver, this);
40755 this.list.on('mousemove', this.onViewMove, this);
40756 this.list.on('scroll', this.onViewScroll, this);
40759 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40762 this.view = new Roo.View(this.list, this.tpl, {
40763 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40766 this.view.on('click', this.onViewClick, this);
40768 this.store.on('beforeload', this.onBeforeLoad, this);
40769 this.store.on('load', this.onLoad, this);
40770 this.store.on('loadexception', this.onLoadException, this);
40772 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40773 "up" : function(e){
40774 this.inKeyMode = true;
40778 "down" : function(e){
40779 if(!this.isExpanded()){
40780 this.onTriggerClick();
40782 this.inKeyMode = true;
40787 "enter" : function(e){
40790 if(this.fireEvent("specialkey", this, e)){
40791 this.onViewClick(false);
40797 "esc" : function(e){
40801 "tab" : function(e){
40804 if(this.fireEvent("specialkey", this, e)){
40805 this.onViewClick(false);
40813 doRelay : function(foo, bar, hname){
40814 if(hname == 'down' || this.scope.isExpanded()){
40815 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40823 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40827 initNumberEvent : function(e)
40829 this.inputEl().on("keydown" , this.fireKey, this);
40830 this.inputEl().on("focus", this.onFocus, this);
40831 this.inputEl().on("blur", this.onBlur, this);
40833 this.inputEl().relayEvent('keyup', this);
40835 if(this.indicator){
40836 this.indicator.addClass('invisible');
40839 this.originalValue = this.getValue();
40841 if(this.validationEvent == 'keyup'){
40842 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40843 this.inputEl().on('keyup', this.filterValidation, this);
40845 else if(this.validationEvent !== false){
40846 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40849 if(this.selectOnFocus){
40850 this.on("focus", this.preFocus, this);
40853 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40854 this.inputEl().on("keypress", this.filterKeys, this);
40856 this.inputEl().relayEvent('keypress', this);
40859 var allowed = "0123456789";
40861 if(this.allowDecimals){
40862 allowed += this.decimalSeparator;
40865 if(this.allowNegative){
40869 if(this.thousandsDelimiter) {
40873 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40875 var keyPress = function(e){
40877 var k = e.getKey();
40879 var c = e.getCharCode();
40882 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40883 allowed.indexOf(String.fromCharCode(c)) === -1
40889 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40893 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40898 this.inputEl().on("keypress", keyPress, this);
40902 onTriggerClick : function(e)
40909 this.loadNext = false;
40911 if(this.isExpanded()){
40916 this.hasFocus = true;
40918 if(this.triggerAction == 'all') {
40919 this.doQuery(this.allQuery, true);
40923 this.doQuery(this.getRawValue());
40926 getCurrency : function()
40928 var v = this.currencyEl().getValue();
40933 restrictHeight : function()
40935 this.list.alignTo(this.currencyEl(), this.listAlign);
40936 this.list.alignTo(this.currencyEl(), this.listAlign);
40939 onViewClick : function(view, doFocus, el, e)
40941 var index = this.view.getSelectedIndexes()[0];
40943 var r = this.store.getAt(index);
40946 this.onSelect(r, index);
40950 onSelect : function(record, index){
40952 if(this.fireEvent('beforeselect', this, record, index) !== false){
40954 this.setFromCurrencyData(index > -1 ? record.data : false);
40958 this.fireEvent('select', this, record, index);
40962 setFromCurrencyData : function(o)
40966 this.lastCurrency = o;
40968 if (this.currencyField) {
40969 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40971 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40974 this.lastSelectionText = currency;
40976 //setting default currency
40977 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40978 this.setCurrency(this.defaultCurrency);
40982 this.setCurrency(currency);
40985 setFromData : function(o)
40989 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40991 this.setFromCurrencyData(c);
40996 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40998 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41001 this.setValue(value);
41005 setCurrency : function(v)
41007 this.currencyValue = v;
41010 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41015 setValue : function(v)
41017 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41023 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41025 this.inputEl().dom.value = (v == '') ? '' :
41026 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41028 if(!this.allowZero && v === '0') {
41029 this.hiddenEl().dom.value = '';
41030 this.inputEl().dom.value = '';
41037 getRawValue : function()
41039 var v = this.inputEl().getValue();
41044 getValue : function()
41046 return this.fixPrecision(this.parseValue(this.getRawValue()));
41049 parseValue : function(value)
41051 if(this.thousandsDelimiter) {
41053 r = new RegExp(",", "g");
41054 value = value.replace(r, "");
41057 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41058 return isNaN(value) ? '' : value;
41062 fixPrecision : function(value)
41064 if(this.thousandsDelimiter) {
41066 r = new RegExp(",", "g");
41067 value = value.replace(r, "");
41070 var nan = isNaN(value);
41072 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41073 return nan ? '' : value;
41075 return parseFloat(value).toFixed(this.decimalPrecision);
41078 decimalPrecisionFcn : function(v)
41080 return Math.floor(v);
41083 validateValue : function(value)
41085 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41089 var num = this.parseValue(value);
41092 this.markInvalid(String.format(this.nanText, value));
41096 if(num < this.minValue){
41097 this.markInvalid(String.format(this.minText, this.minValue));
41101 if(num > this.maxValue){
41102 this.markInvalid(String.format(this.maxText, this.maxValue));
41109 validate : function()
41111 if(this.disabled || this.allowBlank){
41116 var currency = this.getCurrency();
41118 if(this.validateValue(this.getRawValue()) && currency.length){
41123 this.markInvalid();
41127 getName: function()
41132 beforeBlur : function()
41138 var v = this.parseValue(this.getRawValue());
41145 onBlur : function()
41149 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41150 //this.el.removeClass(this.focusClass);
41153 this.hasFocus = false;
41155 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41159 var v = this.getValue();
41161 if(String(v) !== String(this.startValue)){
41162 this.fireEvent('change', this, v, this.startValue);
41165 this.fireEvent("blur", this);
41168 inputEl : function()
41170 return this.el.select('.roo-money-amount-input', true).first();
41173 currencyEl : function()
41175 return this.el.select('.roo-money-currency-input', true).first();
41178 hiddenEl : function()
41180 return this.el.select('input.hidden-number-input',true).first();