2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass('hidden');
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass('hidden');
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
593 * @cfg {String} badge text for badge
594 * @cfg {String} theme (default|glow)
595 * @cfg {Boolean} inverse dark themed version
596 * @cfg {Boolean} toggle is it a slidy toggle button
597 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
598 * @cfg {String} ontext text for on slidy toggle state
599 * @cfg {String} offtext text for off slidy toggle state
600 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
601 * @cfg {Boolean} removeClass remove the standard class..
602 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
605 * Create a new button
606 * @param {Object} config The config object
610 Roo.bootstrap.Button = function(config){
611 Roo.bootstrap.Button.superclass.constructor.call(this, config);
612 this.weightClass = ["btn-default btn-outline-secondary",
624 * When a butotn is pressed
625 * @param {Roo.bootstrap.Button} btn
626 * @param {Roo.EventObject} e
631 * After the button has been toggles
632 * @param {Roo.bootstrap.Button} btn
633 * @param {Roo.EventObject} e
634 * @param {boolean} pressed (also available as button.pressed)
640 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
660 preventDefault: true,
668 getAutoCreate : function(){
676 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
677 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
682 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
684 if (this.toggle == true) {
687 cls: 'slider-frame roo-button',
692 'data-off-text':'OFF',
693 cls: 'slider-button',
699 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
700 cfg.cls += ' '+this.weight;
709 cfg["aria-hidden"] = true;
711 cfg.html = "×";
717 if (this.theme==='default') {
718 cfg.cls = 'btn roo-button';
720 //if (this.parentType != 'Navbar') {
721 this.weight = this.weight.length ? this.weight : 'default';
723 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
725 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
726 var weight = this.weight == 'default' ? 'secondary' : this.weight;
727 cfg.cls += ' btn-' + outline + weight;
728 if (this.weight == 'default') {
730 cfg.cls += ' btn-' + this.weight;
733 } else if (this.theme==='glow') {
736 cfg.cls = 'btn-glow roo-button';
738 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
740 cfg.cls += ' ' + this.weight;
746 this.cls += ' inverse';
750 if (this.active || this.pressed === true) {
751 cfg.cls += ' active';
755 cfg.disabled = 'disabled';
759 Roo.log('changing to ul' );
761 this.glyphicon = 'caret';
764 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
766 //gsRoo.log(this.parentType);
767 if (this.parentType === 'Navbar' && !this.parent().bar) {
768 Roo.log('changing to li?');
777 href : this.href || '#'
780 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
781 cfg.cls += ' dropdown';
788 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
790 if (this.glyphicon) {
791 cfg.html = ' ' + cfg.html;
796 cls: 'glyphicon glyphicon-' + this.glyphicon
806 // cfg.cls='btn roo-button';
810 var value = cfg.html;
815 cls: 'glyphicon glyphicon-' + this.glyphicon,
820 var bw = this.badge_weight.length ? this.badge_weight :
821 (this.weight.length ? this.weight : 'secondary');
822 bw = bw == 'default' ? 'secondary' : bw;
828 cls: 'badge badge-' + bw,
837 cfg.cls += ' dropdown';
838 cfg.html = typeof(cfg.html) != 'undefined' ?
839 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
842 if (cfg.tag !== 'a' && this.href !== '') {
843 throw "Tag must be a to set href.";
844 } else if (this.href.length > 0) {
845 cfg.href = this.href;
848 if(this.removeClass){
853 cfg.target = this.target;
858 initEvents: function() {
859 // Roo.log('init events?');
860 // Roo.log(this.el.dom);
863 if (typeof (this.menu) != 'undefined') {
864 this.menu.parentType = this.xtype;
865 this.menu.triggerEl = this.el;
866 this.addxtype(Roo.apply({}, this.menu));
870 if (this.el.hasClass('roo-button')) {
871 this.el.on('click', this.onClick, this);
873 this.el.select('.roo-button').on('click', this.onClick, this);
876 if(this.removeClass){
877 this.el.on('click', this.onClick, this);
880 this.el.enableDisplayMode();
883 onClick : function(e)
889 Roo.log('button on click ');
890 if(this.preventDefault){
894 if (this.pressed === true || this.pressed === false) {
895 this.toggleActive(e);
899 this.fireEvent('click', this, e);
903 * Enables this button
907 this.disabled = false;
908 this.el.removeClass('disabled');
912 * Disable this button
916 this.disabled = true;
917 this.el.addClass('disabled');
920 * sets the active state on/off,
921 * @param {Boolean} state (optional) Force a particular state
923 setActive : function(v) {
925 this.el[v ? 'addClass' : 'removeClass']('active');
929 * toggles the current active state
931 toggleActive : function(e)
933 this.setActive(!this.pressed);
934 this.fireEvent('toggle', this, e, !this.pressed);
937 * get the current active state
938 * @return {boolean} true if it's active
940 isActive : function()
942 return this.el.hasClass('active');
945 * set the text of the first selected button
947 setText : function(str)
949 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
952 * get the text of the first selected button
956 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
959 setWeight : function(str)
961 this.el.removeClass(this.weightClass);
963 var outline = this.outline ? 'outline-' : '';
964 if (str == 'default') {
965 this.el.addClass('btn-default btn-outline-secondary');
968 this.el.addClass('btn-' + outline + str);
982 * @class Roo.bootstrap.Column
983 * @extends Roo.bootstrap.Component
984 * Bootstrap Column class
985 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
986 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
987 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
988 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
989 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
990 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
991 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
992 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
995 * @cfg {Boolean} hidden (true|false) hide the element
996 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
997 * @cfg {String} fa (ban|check|...) font awesome icon
998 * @cfg {Number} fasize (1|2|....) font awsome size
1000 * @cfg {String} icon (info-sign|check|...) glyphicon name
1002 * @cfg {String} html content of column.
1005 * Create a new Column
1006 * @param {Object} config The config object
1009 Roo.bootstrap.Column = function(config){
1010 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1013 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1031 getAutoCreate : function(){
1032 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1040 ['xs','sm','md','lg'].map(function(size){
1041 //Roo.log( size + ':' + settings[size]);
1043 if (settings[size+'off'] !== false) {
1044 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1047 if (settings[size] === false) {
1051 if (!settings[size]) { // 0 = hidden
1052 cfg.cls += ' hidden-' + size;
1055 cfg.cls += ' col-' + size + '-' + settings[size];
1060 cfg.cls += ' hidden';
1063 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1064 cfg.cls +=' alert alert-' + this.alert;
1068 if (this.html.length) {
1069 cfg.html = this.html;
1073 if (this.fasize > 1) {
1074 fasize = ' fa-' + this.fasize + 'x';
1076 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1081 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1100 * @class Roo.bootstrap.Container
1101 * @extends Roo.bootstrap.Component
1102 * Bootstrap Container class
1103 * @cfg {Boolean} jumbotron is it a jumbotron element
1104 * @cfg {String} html content of element
1105 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1106 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1107 * @cfg {String} header content of header (for panel)
1108 * @cfg {String} footer content of footer (for panel)
1109 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1110 * @cfg {String} tag (header|aside|section) type of HTML tag.
1111 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1112 * @cfg {String} fa font awesome icon
1113 * @cfg {String} icon (info-sign|check|...) glyphicon name
1114 * @cfg {Boolean} hidden (true|false) hide the element
1115 * @cfg {Boolean} expandable (true|false) default false
1116 * @cfg {Boolean} expanded (true|false) default true
1117 * @cfg {String} rheader contet on the right of header
1118 * @cfg {Boolean} clickable (true|false) default false
1122 * Create a new Container
1123 * @param {Object} config The config object
1126 Roo.bootstrap.Container = function(config){
1127 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1133 * After the panel has been expand
1135 * @param {Roo.bootstrap.Container} this
1140 * After the panel has been collapsed
1142 * @param {Roo.bootstrap.Container} this
1147 * When a element is chick
1148 * @param {Roo.bootstrap.Container} this
1149 * @param {Roo.EventObject} e
1155 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1173 getChildContainer : function() {
1179 if (this.panel.length) {
1180 return this.el.select('.panel-body',true).first();
1187 getAutoCreate : function(){
1190 tag : this.tag || 'div',
1194 if (this.jumbotron) {
1195 cfg.cls = 'jumbotron';
1200 // - this is applied by the parent..
1202 // cfg.cls = this.cls + '';
1205 if (this.sticky.length) {
1207 var bd = Roo.get(document.body);
1208 if (!bd.hasClass('bootstrap-sticky')) {
1209 bd.addClass('bootstrap-sticky');
1210 Roo.select('html',true).setStyle('height', '100%');
1213 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1217 if (this.well.length) {
1218 switch (this.well) {
1221 cfg.cls +=' well well-' +this.well;
1230 cfg.cls += ' hidden';
1234 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1235 cfg.cls +=' alert alert-' + this.alert;
1240 if (this.panel.length) {
1241 cfg.cls += ' panel panel-' + this.panel;
1243 if (this.header.length) {
1247 if(this.expandable){
1249 cfg.cls = cfg.cls + ' expandable';
1253 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1261 cls : 'panel-title',
1262 html : (this.expandable ? ' ' : '') + this.header
1266 cls: 'panel-header-right',
1272 cls : 'panel-heading',
1273 style : this.expandable ? 'cursor: pointer' : '',
1281 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1286 if (this.footer.length) {
1288 cls : 'panel-footer',
1297 body.html = this.html || cfg.html;
1298 // prefix with the icons..
1300 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1303 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1308 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1309 cfg.cls = 'container';
1315 initEvents: function()
1317 if(this.expandable){
1318 var headerEl = this.headerEl();
1321 headerEl.on('click', this.onToggleClick, this);
1326 this.el.on('click', this.onClick, this);
1331 onToggleClick : function()
1333 var headerEl = this.headerEl();
1349 if(this.fireEvent('expand', this)) {
1351 this.expanded = true;
1353 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1355 this.el.select('.panel-body',true).first().removeClass('hide');
1357 var toggleEl = this.toggleEl();
1363 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1368 collapse : function()
1370 if(this.fireEvent('collapse', this)) {
1372 this.expanded = false;
1374 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1375 this.el.select('.panel-body',true).first().addClass('hide');
1377 var toggleEl = this.toggleEl();
1383 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1387 toggleEl : function()
1389 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1393 return this.el.select('.panel-heading .fa',true).first();
1396 headerEl : function()
1398 if(!this.el || !this.panel.length || !this.header.length){
1402 return this.el.select('.panel-heading',true).first()
1407 if(!this.el || !this.panel.length){
1411 return this.el.select('.panel-body',true).first()
1414 titleEl : function()
1416 if(!this.el || !this.panel.length || !this.header.length){
1420 return this.el.select('.panel-title',true).first();
1423 setTitle : function(v)
1425 var titleEl = this.titleEl();
1431 titleEl.dom.innerHTML = v;
1434 getTitle : function()
1437 var titleEl = this.titleEl();
1443 return titleEl.dom.innerHTML;
1446 setRightTitle : function(v)
1448 var t = this.el.select('.panel-header-right',true).first();
1454 t.dom.innerHTML = v;
1457 onClick : function(e)
1461 this.fireEvent('click', this, e);
1474 * @class Roo.bootstrap.Img
1475 * @extends Roo.bootstrap.Component
1476 * Bootstrap Img class
1477 * @cfg {Boolean} imgResponsive false | true
1478 * @cfg {String} border rounded | circle | thumbnail
1479 * @cfg {String} src image source
1480 * @cfg {String} alt image alternative text
1481 * @cfg {String} href a tag href
1482 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1483 * @cfg {String} xsUrl xs image source
1484 * @cfg {String} smUrl sm image source
1485 * @cfg {String} mdUrl md image source
1486 * @cfg {String} lgUrl lg image source
1489 * Create a new Input
1490 * @param {Object} config The config object
1493 Roo.bootstrap.Img = function(config){
1494 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1500 * The img click event for the img.
1501 * @param {Roo.EventObject} e
1507 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1509 imgResponsive: true,
1519 getAutoCreate : function()
1521 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1522 return this.createSingleImg();
1527 cls: 'roo-image-responsive-group',
1532 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1534 if(!_this[size + 'Url']){
1540 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1541 html: _this.html || cfg.html,
1542 src: _this[size + 'Url']
1545 img.cls += ' roo-image-responsive-' + size;
1547 var s = ['xs', 'sm', 'md', 'lg'];
1549 s.splice(s.indexOf(size), 1);
1551 Roo.each(s, function(ss){
1552 img.cls += ' hidden-' + ss;
1555 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1556 cfg.cls += ' img-' + _this.border;
1560 cfg.alt = _this.alt;
1573 a.target = _this.target;
1577 cfg.cn.push((_this.href) ? a : img);
1584 createSingleImg : function()
1588 cls: (this.imgResponsive) ? 'img-responsive' : '',
1590 src : 'about:blank' // just incase src get's set to undefined?!?
1593 cfg.html = this.html || cfg.html;
1595 cfg.src = this.src || cfg.src;
1597 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1598 cfg.cls += ' img-' + this.border;
1615 a.target = this.target;
1620 return (this.href) ? a : cfg;
1623 initEvents: function()
1626 this.el.on('click', this.onClick, this);
1631 onClick : function(e)
1633 Roo.log('img onclick');
1634 this.fireEvent('click', this, e);
1637 * Sets the url of the image - used to update it
1638 * @param {String} url the url of the image
1641 setSrc : function(url)
1645 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1646 this.el.dom.src = url;
1650 this.el.select('img', true).first().dom.src = url;
1666 * @class Roo.bootstrap.Link
1667 * @extends Roo.bootstrap.Component
1668 * Bootstrap Link Class
1669 * @cfg {String} alt image alternative text
1670 * @cfg {String} href a tag href
1671 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1672 * @cfg {String} html the content of the link.
1673 * @cfg {String} anchor name for the anchor link
1674 * @cfg {String} fa - favicon
1676 * @cfg {Boolean} preventDefault (true | false) default false
1680 * Create a new Input
1681 * @param {Object} config The config object
1684 Roo.bootstrap.Link = function(config){
1685 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1691 * The img click event for the img.
1692 * @param {Roo.EventObject} e
1698 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1702 preventDefault: false,
1708 getAutoCreate : function()
1710 var html = this.html || '';
1712 if (this.fa !== false) {
1713 html = '<i class="fa fa-' + this.fa + '"></i>';
1718 // anchor's do not require html/href...
1719 if (this.anchor === false) {
1721 cfg.href = this.href || '#';
1723 cfg.name = this.anchor;
1724 if (this.html !== false || this.fa !== false) {
1727 if (this.href !== false) {
1728 cfg.href = this.href;
1732 if(this.alt !== false){
1737 if(this.target !== false) {
1738 cfg.target = this.target;
1744 initEvents: function() {
1746 if(!this.href || this.preventDefault){
1747 this.el.on('click', this.onClick, this);
1751 onClick : function(e)
1753 if(this.preventDefault){
1756 //Roo.log('img onclick');
1757 this.fireEvent('click', this, e);
1770 * @class Roo.bootstrap.Header
1771 * @extends Roo.bootstrap.Component
1772 * Bootstrap Header class
1773 * @cfg {String} html content of header
1774 * @cfg {Number} level (1|2|3|4|5|6) default 1
1777 * Create a new Header
1778 * @param {Object} config The config object
1782 Roo.bootstrap.Header = function(config){
1783 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1786 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1794 getAutoCreate : function(){
1799 tag: 'h' + (1 *this.level),
1800 html: this.html || ''
1812 * Ext JS Library 1.1.1
1813 * Copyright(c) 2006-2007, Ext JS, LLC.
1815 * Originally Released Under LGPL - original licence link has changed is not relivant.
1818 * <script type="text/javascript">
1822 * @class Roo.bootstrap.MenuMgr
1823 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1826 Roo.bootstrap.MenuMgr = function(){
1827 var menus, active, groups = {}, attached = false, lastShow = new Date();
1829 // private - called when first menu is created
1832 active = new Roo.util.MixedCollection();
1833 Roo.get(document).addKeyListener(27, function(){
1834 if(active.length > 0){
1842 if(active && active.length > 0){
1843 var c = active.clone();
1853 if(active.length < 1){
1854 Roo.get(document).un("mouseup", onMouseDown);
1862 var last = active.last();
1863 lastShow = new Date();
1866 Roo.get(document).on("mouseup", onMouseDown);
1871 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1872 m.parentMenu.activeChild = m;
1873 }else if(last && last.isVisible()){
1874 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1879 function onBeforeHide(m){
1881 m.activeChild.hide();
1883 if(m.autoHideTimer){
1884 clearTimeout(m.autoHideTimer);
1885 delete m.autoHideTimer;
1890 function onBeforeShow(m){
1891 var pm = m.parentMenu;
1892 if(!pm && !m.allowOtherMenus){
1894 }else if(pm && pm.activeChild && active != m){
1895 pm.activeChild.hide();
1899 // private this should really trigger on mouseup..
1900 function onMouseDown(e){
1901 Roo.log("on Mouse Up");
1903 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1904 Roo.log("MenuManager hideAll");
1913 function onBeforeCheck(mi, state){
1915 var g = groups[mi.group];
1916 for(var i = 0, l = g.length; i < l; i++){
1918 g[i].setChecked(false);
1927 * Hides all menus that are currently visible
1929 hideAll : function(){
1934 register : function(menu){
1938 menus[menu.id] = menu;
1939 menu.on("beforehide", onBeforeHide);
1940 menu.on("hide", onHide);
1941 menu.on("beforeshow", onBeforeShow);
1942 menu.on("show", onShow);
1944 if(g && menu.events["checkchange"]){
1948 groups[g].push(menu);
1949 menu.on("checkchange", onCheck);
1954 * Returns a {@link Roo.menu.Menu} object
1955 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1956 * be used to generate and return a new Menu instance.
1958 get : function(menu){
1959 if(typeof menu == "string"){ // menu id
1961 }else if(menu.events){ // menu instance
1964 /*else if(typeof menu.length == 'number'){ // array of menu items?
1965 return new Roo.bootstrap.Menu({items:menu});
1966 }else{ // otherwise, must be a config
1967 return new Roo.bootstrap.Menu(menu);
1974 unregister : function(menu){
1975 delete menus[menu.id];
1976 menu.un("beforehide", onBeforeHide);
1977 menu.un("hide", onHide);
1978 menu.un("beforeshow", onBeforeShow);
1979 menu.un("show", onShow);
1981 if(g && menu.events["checkchange"]){
1982 groups[g].remove(menu);
1983 menu.un("checkchange", onCheck);
1988 registerCheckable : function(menuItem){
1989 var g = menuItem.group;
1994 groups[g].push(menuItem);
1995 menuItem.on("beforecheckchange", onBeforeCheck);
2000 unregisterCheckable : function(menuItem){
2001 var g = menuItem.group;
2003 groups[g].remove(menuItem);
2004 menuItem.un("beforecheckchange", onBeforeCheck);
2016 * @class Roo.bootstrap.Menu
2017 * @extends Roo.bootstrap.Component
2018 * Bootstrap Menu class - container for MenuItems
2019 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2020 * @cfg {bool} hidden if the menu should be hidden when rendered.
2021 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2022 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2026 * @param {Object} config The config object
2030 Roo.bootstrap.Menu = function(config){
2031 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2032 if (this.registerMenu && this.type != 'treeview') {
2033 Roo.bootstrap.MenuMgr.register(this);
2040 * Fires before this menu is displayed
2041 * @param {Roo.menu.Menu} this
2046 * Fires before this menu is hidden
2047 * @param {Roo.menu.Menu} this
2052 * Fires after this menu is displayed
2053 * @param {Roo.menu.Menu} this
2058 * Fires after this menu is hidden
2059 * @param {Roo.menu.Menu} this
2064 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2065 * @param {Roo.menu.Menu} this
2066 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2067 * @param {Roo.EventObject} e
2072 * Fires when the mouse is hovering over this menu
2073 * @param {Roo.menu.Menu} this
2074 * @param {Roo.EventObject} e
2075 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2080 * Fires when the mouse exits this menu
2081 * @param {Roo.menu.Menu} this
2082 * @param {Roo.EventObject} e
2083 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2088 * Fires when a menu item contained in this menu is clicked
2089 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2090 * @param {Roo.EventObject} e
2094 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2097 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2101 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2104 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2106 registerMenu : true,
2108 menuItems :false, // stores the menu items..
2118 getChildContainer : function() {
2122 getAutoCreate : function(){
2124 //if (['right'].indexOf(this.align)!==-1) {
2125 // cfg.cn[1].cls += ' pull-right'
2131 cls : 'dropdown-menu' ,
2132 style : 'z-index:1000'
2136 if (this.type === 'submenu') {
2137 cfg.cls = 'submenu active';
2139 if (this.type === 'treeview') {
2140 cfg.cls = 'treeview-menu';
2145 initEvents : function() {
2147 // Roo.log("ADD event");
2148 // Roo.log(this.triggerEl.dom);
2150 this.triggerEl.on('click', this.onTriggerClick, this);
2152 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2155 if (this.triggerEl.hasClass('nav-item')) {
2156 // dropdown toggle on the 'a' in BS4?
2157 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2159 this.triggerEl.addClass('dropdown-toggle');
2162 this.el.on('touchstart' , this.onTouch, this);
2164 this.el.on('click' , this.onClick, this);
2166 this.el.on("mouseover", this.onMouseOver, this);
2167 this.el.on("mouseout", this.onMouseOut, this);
2171 findTargetItem : function(e)
2173 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2177 //Roo.log(t); Roo.log(t.id);
2179 //Roo.log(this.menuitems);
2180 return this.menuitems.get(t.id);
2182 //return this.items.get(t.menuItemId);
2188 onTouch : function(e)
2190 Roo.log("menu.onTouch");
2191 //e.stopEvent(); this make the user popdown broken
2195 onClick : function(e)
2197 Roo.log("menu.onClick");
2199 var t = this.findTargetItem(e);
2200 if(!t || t.isContainer){
2205 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2206 if(t == this.activeItem && t.shouldDeactivate(e)){
2207 this.activeItem.deactivate();
2208 delete this.activeItem;
2212 this.setActiveItem(t, true);
2220 Roo.log('pass click event');
2224 this.fireEvent("click", this, t, e);
2228 if(!t.href.length || t.href == '#'){
2229 (function() { _this.hide(); }).defer(100);
2234 onMouseOver : function(e){
2235 var t = this.findTargetItem(e);
2238 // if(t.canActivate && !t.disabled){
2239 // this.setActiveItem(t, true);
2243 this.fireEvent("mouseover", this, e, t);
2245 isVisible : function(){
2246 return !this.hidden;
2248 onMouseOut : function(e){
2249 var t = this.findTargetItem(e);
2252 // if(t == this.activeItem && t.shouldDeactivate(e)){
2253 // this.activeItem.deactivate();
2254 // delete this.activeItem;
2257 this.fireEvent("mouseout", this, e, t);
2262 * Displays this menu relative to another element
2263 * @param {String/HTMLElement/Roo.Element} element The element to align to
2264 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2265 * the element (defaults to this.defaultAlign)
2266 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2268 show : function(el, pos, parentMenu){
2269 this.parentMenu = parentMenu;
2273 this.fireEvent("beforeshow", this);
2274 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2277 * Displays this menu at a specific xy position
2278 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2279 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2281 showAt : function(xy, parentMenu, /* private: */_e){
2282 this.parentMenu = parentMenu;
2287 this.fireEvent("beforeshow", this);
2288 //xy = this.el.adjustForConstraints(xy);
2292 this.hideMenuItems();
2293 this.hidden = false;
2294 this.triggerEl.addClass('open');
2295 this.el.addClass('show');
2297 // reassign x when hitting right
2298 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2299 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2302 // reassign y when hitting bottom
2303 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2304 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2307 // but the list may align on trigger left or trigger top... should it be a properity?
2309 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2314 this.fireEvent("show", this);
2320 this.doFocus.defer(50, this);
2324 doFocus : function(){
2326 this.focusEl.focus();
2331 * Hides this menu and optionally all parent menus
2332 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2334 hide : function(deep)
2337 this.hideMenuItems();
2338 if(this.el && this.isVisible()){
2339 this.fireEvent("beforehide", this);
2340 if(this.activeItem){
2341 this.activeItem.deactivate();
2342 this.activeItem = null;
2344 this.triggerEl.removeClass('open');;
2345 this.el.removeClass('show');
2347 this.fireEvent("hide", this);
2349 if(deep === true && this.parentMenu){
2350 this.parentMenu.hide(true);
2354 onTriggerClick : function(e)
2356 Roo.log('trigger click');
2358 var target = e.getTarget();
2360 Roo.log(target.nodeName.toLowerCase());
2362 if(target.nodeName.toLowerCase() === 'i'){
2368 onTriggerPress : function(e)
2370 Roo.log('trigger press');
2371 //Roo.log(e.getTarget());
2372 // Roo.log(this.triggerEl.dom);
2374 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2375 var pel = Roo.get(e.getTarget());
2376 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2377 Roo.log('is treeview or dropdown?');
2381 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2385 if (this.isVisible()) {
2390 this.show(this.triggerEl, false, false);
2393 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2400 hideMenuItems : function()
2402 Roo.log("hide Menu Items");
2406 //$(backdrop).remove()
2407 this.el.select('.open',true).each(function(aa) {
2409 aa.removeClass('open');
2410 //var parent = getParent($(this))
2411 //var relatedTarget = { relatedTarget: this }
2413 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2414 //if (e.isDefaultPrevented()) return
2415 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2418 addxtypeChild : function (tree, cntr) {
2419 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2421 this.menuitems.add(comp);
2433 this.getEl().dom.innerHTML = '';
2434 this.menuitems.clear();
2448 * @class Roo.bootstrap.MenuItem
2449 * @extends Roo.bootstrap.Component
2450 * Bootstrap MenuItem class
2451 * @cfg {String} html the menu label
2452 * @cfg {String} href the link
2453 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2454 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2455 * @cfg {Boolean} active used on sidebars to highlight active itesm
2456 * @cfg {String} fa favicon to show on left of menu item.
2457 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2461 * Create a new MenuItem
2462 * @param {Object} config The config object
2466 Roo.bootstrap.MenuItem = function(config){
2467 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2472 * The raw click event for the entire grid.
2473 * @param {Roo.bootstrap.MenuItem} this
2474 * @param {Roo.EventObject} e
2480 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2484 preventDefault: false,
2485 isContainer : false,
2489 getAutoCreate : function(){
2491 if(this.isContainer){
2494 cls: 'dropdown-menu-item dropdown-item'
2508 if (this.fa !== false) {
2511 cls : 'fa fa-' + this.fa
2520 cls: 'dropdown-menu-item dropdown-item',
2523 if (this.parent().type == 'treeview') {
2524 cfg.cls = 'treeview-menu';
2527 cfg.cls += ' active';
2532 anc.href = this.href || cfg.cn[0].href ;
2533 ctag.html = this.html || cfg.cn[0].html ;
2537 initEvents: function()
2539 if (this.parent().type == 'treeview') {
2540 this.el.select('a').on('click', this.onClick, this);
2544 this.menu.parentType = this.xtype;
2545 this.menu.triggerEl = this.el;
2546 this.menu = this.addxtype(Roo.apply({}, this.menu));
2550 onClick : function(e)
2552 Roo.log('item on click ');
2554 if(this.preventDefault){
2557 //this.parent().hideMenuItems();
2559 this.fireEvent('click', this, e);
2578 * @class Roo.bootstrap.MenuSeparator
2579 * @extends Roo.bootstrap.Component
2580 * Bootstrap MenuSeparator class
2583 * Create a new MenuItem
2584 * @param {Object} config The config object
2588 Roo.bootstrap.MenuSeparator = function(config){
2589 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2592 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2594 getAutoCreate : function(){
2613 * @class Roo.bootstrap.Modal
2614 * @extends Roo.bootstrap.Component
2615 * Bootstrap Modal class
2616 * @cfg {String} title Title of dialog
2617 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2618 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2619 * @cfg {Boolean} specificTitle default false
2620 * @cfg {Array} buttons Array of buttons or standard button set..
2621 * @cfg {String} buttonPosition (left|right|center) default right
2622 * @cfg {Boolean} animate default true
2623 * @cfg {Boolean} allow_close default true
2624 * @cfg {Boolean} fitwindow default false
2625 * @cfg {String} size (sm|lg) default empty
2626 * @cfg {Number} max_width set the max width of modal
2630 * Create a new Modal Dialog
2631 * @param {Object} config The config object
2634 Roo.bootstrap.Modal = function(config){
2635 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2640 * The raw btnclick event for the button
2641 * @param {Roo.EventObject} e
2646 * Fire when dialog resize
2647 * @param {Roo.bootstrap.Modal} this
2648 * @param {Roo.EventObject} e
2652 this.buttons = this.buttons || [];
2655 this.tmpl = Roo.factory(this.tmpl);
2660 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2662 title : 'test dialog',
2672 specificTitle: false,
2674 buttonPosition: 'right',
2697 onRender : function(ct, position)
2699 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2702 var cfg = Roo.apply({}, this.getAutoCreate());
2705 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2707 //if (!cfg.name.length) {
2711 cfg.cls += ' ' + this.cls;
2714 cfg.style = this.style;
2716 this.el = Roo.get(document.body).createChild(cfg, position);
2718 //var type = this.el.dom.type;
2721 if(this.tabIndex !== undefined){
2722 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2725 this.dialogEl = this.el.select('.modal-dialog',true).first();
2726 this.bodyEl = this.el.select('.modal-body',true).first();
2727 this.closeEl = this.el.select('.modal-header .close', true).first();
2728 this.headerEl = this.el.select('.modal-header',true).first();
2729 this.titleEl = this.el.select('.modal-title',true).first();
2730 this.footerEl = this.el.select('.modal-footer',true).first();
2732 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2734 //this.el.addClass("x-dlg-modal");
2736 if (this.buttons.length) {
2737 Roo.each(this.buttons, function(bb) {
2738 var b = Roo.apply({}, bb);
2739 b.xns = b.xns || Roo.bootstrap;
2740 b.xtype = b.xtype || 'Button';
2741 if (typeof(b.listeners) == 'undefined') {
2742 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2745 var btn = Roo.factory(b);
2747 btn.render(this.el.select('.modal-footer div').first());
2751 // render the children.
2754 if(typeof(this.items) != 'undefined'){
2755 var items = this.items;
2758 for(var i =0;i < items.length;i++) {
2759 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2763 this.items = nitems;
2765 // where are these used - they used to be body/close/footer
2769 //this.el.addClass([this.fieldClass, this.cls]);
2773 getAutoCreate : function()
2777 html : this.html || ''
2782 cls : 'modal-title',
2786 if(this.specificTitle){
2792 if (this.allow_close && Roo.bootstrap.version == 3) {
2802 if (this.allow_close && Roo.bootstrap.version == 4) {
2812 if(this.size.length){
2813 size = 'modal-' + this.size;
2820 cls: "modal-dialog " + size,
2823 cls : "modal-content",
2826 cls : 'modal-header',
2831 cls : 'modal-footer',
2835 cls: 'btn-' + this.buttonPosition
2852 modal.cls += ' fade';
2858 getChildContainer : function() {
2863 getButtonContainer : function() {
2864 return this.el.select('.modal-footer div',true).first();
2867 initEvents : function()
2869 if (this.allow_close) {
2870 this.closeEl.on('click', this.hide, this);
2872 Roo.EventManager.onWindowResize(this.resize, this, true);
2879 this.maskEl.setSize(
2880 Roo.lib.Dom.getViewWidth(true),
2881 Roo.lib.Dom.getViewHeight(true)
2884 if (this.fitwindow) {
2886 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2887 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2892 if(this.max_width !== 0) {
2894 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2897 this.setSize(w, this.height);
2901 if(this.max_height) {
2902 this.setSize(w,Math.min(
2904 Roo.lib.Dom.getViewportHeight(true) - 60
2910 if(!this.fit_content) {
2911 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2915 this.setSize(w, Math.min(
2917 this.headerEl.getHeight() +
2918 this.footerEl.getHeight() +
2919 this.getChildHeight(this.bodyEl.dom.childNodes),
2920 Roo.lib.Dom.getViewportHeight(true) - 60)
2926 setSize : function(w,h)
2937 if (!this.rendered) {
2941 //this.el.setStyle('display', 'block');
2942 this.el.removeClass('hideing');
2943 this.el.dom.style.display='block';
2945 Roo.get(document.body).addClass('modal-open');
2947 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2950 this.el.addClass('show');
2951 this.el.addClass('in');
2954 this.el.addClass('show');
2955 this.el.addClass('in');
2958 // not sure how we can show data in here..
2960 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2963 Roo.get(document.body).addClass("x-body-masked");
2965 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2966 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2967 this.maskEl.dom.style.display = 'block';
2968 this.maskEl.addClass('show');
2973 this.fireEvent('show', this);
2975 // set zindex here - otherwise it appears to be ignored...
2976 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2979 this.items.forEach( function(e) {
2980 e.layout ? e.layout() : false;
2988 if(this.fireEvent("beforehide", this) !== false){
2990 this.maskEl.removeClass('show');
2992 this.maskEl.dom.style.display = '';
2993 Roo.get(document.body).removeClass("x-body-masked");
2994 this.el.removeClass('in');
2995 this.el.select('.modal-dialog', true).first().setStyle('transform','');
2997 if(this.animate){ // why
2998 this.el.addClass('hideing');
2999 this.el.removeClass('show');
3001 if (!this.el.hasClass('hideing')) {
3002 return; // it's been shown again...
3005 this.el.dom.style.display='';
3007 Roo.get(document.body).removeClass('modal-open');
3008 this.el.removeClass('hideing');
3012 this.el.removeClass('show');
3013 this.el.dom.style.display='';
3014 Roo.get(document.body).removeClass('modal-open');
3017 this.fireEvent('hide', this);
3020 isVisible : function()
3023 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3027 addButton : function(str, cb)
3031 var b = Roo.apply({}, { html : str } );
3032 b.xns = b.xns || Roo.bootstrap;
3033 b.xtype = b.xtype || 'Button';
3034 if (typeof(b.listeners) == 'undefined') {
3035 b.listeners = { click : cb.createDelegate(this) };
3038 var btn = Roo.factory(b);
3040 btn.render(this.el.select('.modal-footer div').first());
3046 setDefaultButton : function(btn)
3048 //this.el.select('.modal-footer').()
3052 resizeTo: function(w,h)
3056 this.dialogEl.setWidth(w);
3057 if (this.diff === false) {
3058 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3061 this.bodyEl.setHeight(h - this.diff);
3063 this.fireEvent('resize', this);
3066 setContentSize : function(w, h)
3070 onButtonClick: function(btn,e)
3073 this.fireEvent('btnclick', btn.name, e);
3076 * Set the title of the Dialog
3077 * @param {String} str new Title
3079 setTitle: function(str) {
3080 this.titleEl.dom.innerHTML = str;
3083 * Set the body of the Dialog
3084 * @param {String} str new Title
3086 setBody: function(str) {
3087 this.bodyEl.dom.innerHTML = str;
3090 * Set the body of the Dialog using the template
3091 * @param {Obj} data - apply this data to the template and replace the body contents.
3093 applyBody: function(obj)
3096 Roo.log("Error - using apply Body without a template");
3099 this.tmpl.overwrite(this.bodyEl, obj);
3102 getChildHeight : function(child_nodes)
3106 child_nodes.length == 0
3111 var child_height = 0;
3113 for(var i = 0; i < child_nodes.length; i++) {
3116 * for modal with tabs...
3117 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3119 var layout_childs = child_nodes[i].childNodes;
3121 for(var j = 0; j < layout_childs.length; j++) {
3123 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3125 var layout_body_childs = layout_childs[j].childNodes;
3127 for(var k = 0; k < layout_body_childs.length; k++) {
3129 if(layout_body_childs[k].classList.contains('navbar')) {
3130 child_height += layout_body_childs[k].offsetHeight;
3134 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3136 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3138 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3140 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3141 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3156 child_height += child_nodes[i].offsetHeight;
3157 // Roo.log(child_nodes[i].offsetHeight);
3160 return child_height;
3166 Roo.apply(Roo.bootstrap.Modal, {
3168 * Button config that displays a single OK button
3177 * Button config that displays Yes and No buttons
3193 * Button config that displays OK and Cancel buttons
3208 * Button config that displays Yes, No and Cancel buttons
3232 * messagebox - can be used as a replace
3236 * @class Roo.MessageBox
3237 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3241 Roo.Msg.alert('Status', 'Changes saved successfully.');
3243 // Prompt for user data:
3244 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3246 // process text value...
3250 // Show a dialog using config options:
3252 title:'Save Changes?',
3253 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3254 buttons: Roo.Msg.YESNOCANCEL,
3261 Roo.bootstrap.MessageBox = function(){
3262 var dlg, opt, mask, waitTimer;
3263 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3264 var buttons, activeTextEl, bwidth;
3268 var handleButton = function(button){
3270 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3274 var handleHide = function(){
3276 dlg.el.removeClass(opt.cls);
3279 // Roo.TaskMgr.stop(waitTimer);
3280 // waitTimer = null;
3285 var updateButtons = function(b){
3288 buttons["ok"].hide();
3289 buttons["cancel"].hide();
3290 buttons["yes"].hide();
3291 buttons["no"].hide();
3292 //dlg.footer.dom.style.display = 'none';
3295 dlg.footerEl.dom.style.display = '';
3296 for(var k in buttons){
3297 if(typeof buttons[k] != "function"){
3300 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3301 width += buttons[k].el.getWidth()+15;
3311 var handleEsc = function(d, k, e){
3312 if(opt && opt.closable !== false){
3322 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3323 * @return {Roo.BasicDialog} The BasicDialog element
3325 getDialog : function(){
3327 dlg = new Roo.bootstrap.Modal( {
3330 //constraintoviewport:false,
3332 //collapsible : false,
3337 //buttonAlign:"center",
3338 closeClick : function(){
3339 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3342 handleButton("cancel");
3347 dlg.on("hide", handleHide);
3349 //dlg.addKeyListener(27, handleEsc);
3351 this.buttons = buttons;
3352 var bt = this.buttonText;
3353 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3354 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3355 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3356 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3358 bodyEl = dlg.bodyEl.createChild({
3360 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3361 '<textarea class="roo-mb-textarea"></textarea>' +
3362 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3364 msgEl = bodyEl.dom.firstChild;
3365 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3366 textboxEl.enableDisplayMode();
3367 textboxEl.addKeyListener([10,13], function(){
3368 if(dlg.isVisible() && opt && opt.buttons){
3371 }else if(opt.buttons.yes){
3372 handleButton("yes");
3376 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3377 textareaEl.enableDisplayMode();
3378 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3379 progressEl.enableDisplayMode();
3381 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3382 var pf = progressEl.dom.firstChild;
3384 pp = Roo.get(pf.firstChild);
3385 pp.setHeight(pf.offsetHeight);
3393 * Updates the message box body text
3394 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3395 * the XHTML-compliant non-breaking space character '&#160;')
3396 * @return {Roo.MessageBox} This message box
3398 updateText : function(text)
3400 if(!dlg.isVisible() && !opt.width){
3401 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3402 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3404 msgEl.innerHTML = text || ' ';
3406 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3407 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3409 Math.min(opt.width || cw , this.maxWidth),
3410 Math.max(opt.minWidth || this.minWidth, bwidth)
3413 activeTextEl.setWidth(w);
3415 if(dlg.isVisible()){
3416 dlg.fixedcenter = false;
3418 // to big, make it scroll. = But as usual stupid IE does not support
3421 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3422 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3423 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3425 bodyEl.dom.style.height = '';
3426 bodyEl.dom.style.overflowY = '';
3429 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3431 bodyEl.dom.style.overflowX = '';
3434 dlg.setContentSize(w, bodyEl.getHeight());
3435 if(dlg.isVisible()){
3436 dlg.fixedcenter = true;
3442 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3443 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3444 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3445 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3446 * @return {Roo.MessageBox} This message box
3448 updateProgress : function(value, text){
3450 this.updateText(text);
3453 if (pp) { // weird bug on my firefox - for some reason this is not defined
3454 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3455 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3461 * Returns true if the message box is currently displayed
3462 * @return {Boolean} True if the message box is visible, else false
3464 isVisible : function(){
3465 return dlg && dlg.isVisible();
3469 * Hides the message box if it is displayed
3472 if(this.isVisible()){
3478 * Displays a new message box, or reinitializes an existing message box, based on the config options
3479 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3480 * The following config object properties are supported:
3482 Property Type Description
3483 ---------- --------------- ------------------------------------------------------------------------------------
3484 animEl String/Element An id or Element from which the message box should animate as it opens and
3485 closes (defaults to undefined)
3486 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3487 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3488 closable Boolean False to hide the top-right close button (defaults to true). Note that
3489 progress and wait dialogs will ignore this property and always hide the
3490 close button as they can only be closed programmatically.
3491 cls String A custom CSS class to apply to the message box element
3492 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3493 displayed (defaults to 75)
3494 fn Function A callback function to execute after closing the dialog. The arguments to the
3495 function will be btn (the name of the button that was clicked, if applicable,
3496 e.g. "ok"), and text (the value of the active text field, if applicable).
3497 Progress and wait dialogs will ignore this option since they do not respond to
3498 user actions and can only be closed programmatically, so any required function
3499 should be called by the same code after it closes the dialog.
3500 icon String A CSS class that provides a background image to be used as an icon for
3501 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3502 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3503 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3504 modal Boolean False to allow user interaction with the page while the message box is
3505 displayed (defaults to true)
3506 msg String A string that will replace the existing message box body text (defaults
3507 to the XHTML-compliant non-breaking space character ' ')
3508 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3509 progress Boolean True to display a progress bar (defaults to false)
3510 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3511 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3512 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3513 title String The title text
3514 value String The string value to set into the active textbox element if displayed
3515 wait Boolean True to display a progress bar (defaults to false)
3516 width Number The width of the dialog in pixels
3523 msg: 'Please enter your address:',
3525 buttons: Roo.MessageBox.OKCANCEL,
3528 animEl: 'addAddressBtn'
3531 * @param {Object} config Configuration options
3532 * @return {Roo.MessageBox} This message box
3534 show : function(options)
3537 // this causes nightmares if you show one dialog after another
3538 // especially on callbacks..
3540 if(this.isVisible()){
3543 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3544 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3545 Roo.log("New Dialog Message:" + options.msg )
3546 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3547 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3550 var d = this.getDialog();
3552 d.setTitle(opt.title || " ");
3553 d.closeEl.setDisplayed(opt.closable !== false);
3554 activeTextEl = textboxEl;
3555 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3560 textareaEl.setHeight(typeof opt.multiline == "number" ?
3561 opt.multiline : this.defaultTextHeight);
3562 activeTextEl = textareaEl;
3571 progressEl.setDisplayed(opt.progress === true);
3572 this.updateProgress(0);
3573 activeTextEl.dom.value = opt.value || "";
3575 dlg.setDefaultButton(activeTextEl);
3577 var bs = opt.buttons;
3581 }else if(bs && bs.yes){
3582 db = buttons["yes"];
3584 dlg.setDefaultButton(db);
3586 bwidth = updateButtons(opt.buttons);
3587 this.updateText(opt.msg);
3589 d.el.addClass(opt.cls);
3591 d.proxyDrag = opt.proxyDrag === true;
3592 d.modal = opt.modal !== false;
3593 d.mask = opt.modal !== false ? mask : false;
3595 // force it to the end of the z-index stack so it gets a cursor in FF
3596 document.body.appendChild(dlg.el.dom);
3597 d.animateTarget = null;
3598 d.show(options.animEl);
3604 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3605 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3606 * and closing the message box when the process is complete.
3607 * @param {String} title The title bar text
3608 * @param {String} msg The message box body text
3609 * @return {Roo.MessageBox} This message box
3611 progress : function(title, msg){
3618 minWidth: this.minProgressWidth,
3625 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3626 * If a callback function is passed it will be called after the user clicks the button, and the
3627 * id of the button that was clicked will be passed as the only parameter to the callback
3628 * (could also be the top-right close button).
3629 * @param {String} title The title bar text
3630 * @param {String} msg The message box body text
3631 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3632 * @param {Object} scope (optional) The scope of the callback function
3633 * @return {Roo.MessageBox} This message box
3635 alert : function(title, msg, fn, scope)
3650 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3651 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3652 * You are responsible for closing the message box when the process is complete.
3653 * @param {String} msg The message box body text
3654 * @param {String} title (optional) The title bar text
3655 * @return {Roo.MessageBox} This message box
3657 wait : function(msg, title){
3668 waitTimer = Roo.TaskMgr.start({
3670 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3678 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3679 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3680 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3681 * @param {String} title The title bar text
3682 * @param {String} msg The message box body text
3683 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3684 * @param {Object} scope (optional) The scope of the callback function
3685 * @return {Roo.MessageBox} This message box
3687 confirm : function(title, msg, fn, scope){
3691 buttons: this.YESNO,
3700 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3701 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3702 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3703 * (could also be the top-right close button) and the text that was entered will be passed as the two
3704 * parameters to the callback.
3705 * @param {String} title The title bar text
3706 * @param {String} msg The message box body text
3707 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3708 * @param {Object} scope (optional) The scope of the callback function
3709 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3710 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3711 * @return {Roo.MessageBox} This message box
3713 prompt : function(title, msg, fn, scope, multiline){
3717 buttons: this.OKCANCEL,
3722 multiline: multiline,
3729 * Button config that displays a single OK button
3734 * Button config that displays Yes and No buttons
3737 YESNO : {yes:true, no:true},
3739 * Button config that displays OK and Cancel buttons
3742 OKCANCEL : {ok:true, cancel:true},
3744 * Button config that displays Yes, No and Cancel buttons
3747 YESNOCANCEL : {yes:true, no:true, cancel:true},
3750 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3753 defaultTextHeight : 75,
3755 * The maximum width in pixels of the message box (defaults to 600)
3760 * The minimum width in pixels of the message box (defaults to 100)
3765 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3766 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3769 minProgressWidth : 250,
3771 * An object containing the default button text strings that can be overriden for localized language support.
3772 * Supported properties are: ok, cancel, yes and no.
3773 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3786 * Shorthand for {@link Roo.MessageBox}
3788 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3789 Roo.Msg = Roo.Msg || Roo.MessageBox;
3798 * @class Roo.bootstrap.Navbar
3799 * @extends Roo.bootstrap.Component
3800 * Bootstrap Navbar class
3803 * Create a new Navbar
3804 * @param {Object} config The config object
3808 Roo.bootstrap.Navbar = function(config){
3809 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3813 * @event beforetoggle
3814 * Fire before toggle the menu
3815 * @param {Roo.EventObject} e
3817 "beforetoggle" : true
3821 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3830 getAutoCreate : function(){
3833 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3837 initEvents :function ()
3839 //Roo.log(this.el.select('.navbar-toggle',true));
3840 this.el.select('.navbar-toggle',true).on('click', function() {
3841 if(this.fireEvent('beforetoggle', this) !== false){
3842 this.el.select('.navbar-collapse',true).toggleClass('in');
3852 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3854 var size = this.el.getSize();
3855 this.maskEl.setSize(size.width, size.height);
3856 this.maskEl.enableDisplayMode("block");
3865 getChildContainer : function()
3867 if (this.el.select('.collapse').getCount()) {
3868 return this.el.select('.collapse',true).first();
3901 * @class Roo.bootstrap.NavSimplebar
3902 * @extends Roo.bootstrap.Navbar
3903 * Bootstrap Sidebar class
3905 * @cfg {Boolean} inverse is inverted color
3907 * @cfg {String} type (nav | pills | tabs)
3908 * @cfg {Boolean} arrangement stacked | justified
3909 * @cfg {String} align (left | right) alignment
3911 * @cfg {Boolean} main (true|false) main nav bar? default false
3912 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3914 * @cfg {String} tag (header|footer|nav|div) default is nav
3916 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3920 * Create a new Sidebar
3921 * @param {Object} config The config object
3925 Roo.bootstrap.NavSimplebar = function(config){
3926 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3929 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3945 getAutoCreate : function(){
3949 tag : this.tag || 'div',
3950 cls : 'navbar navbar-expand-lg'
3952 if (['light','white'].indexOf(this.weight) > -1) {
3953 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
3955 cfg.cls += ' bg-' + this.weight;
3967 this.type = this.type || 'nav';
3968 if (['tabs','pills'].indexOf(this.type)!==-1) {
3969 cfg.cn[0].cls += ' nav-' + this.type
3973 if (this.type!=='nav') {
3974 Roo.log('nav type must be nav/tabs/pills')
3976 cfg.cn[0].cls += ' navbar-nav'
3982 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3983 cfg.cn[0].cls += ' nav-' + this.arrangement;
3987 if (this.align === 'right') {
3988 cfg.cn[0].cls += ' navbar-right';
3992 cfg.cls += ' navbar-inverse';
4016 * navbar-expand-md fixed-top
4020 * @class Roo.bootstrap.NavHeaderbar
4021 * @extends Roo.bootstrap.NavSimplebar
4022 * Bootstrap Sidebar class
4024 * @cfg {String} brand what is brand
4025 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4026 * @cfg {String} brand_href href of the brand
4027 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4028 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4029 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4030 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4033 * Create a new Sidebar
4034 * @param {Object} config The config object
4038 Roo.bootstrap.NavHeaderbar = function(config){
4039 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4043 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4050 desktopCenter : false,
4053 getAutoCreate : function(){
4056 tag: this.nav || 'nav',
4057 cls: 'navbar navbar-expand-md',
4063 if (this.desktopCenter) {
4064 cn.push({cls : 'container', cn : []});
4071 cls: 'navbar-header',
4076 cls: 'navbar-toggle navbar-toggler',
4077 'data-toggle': 'collapse',
4082 html: 'Toggle navigation'
4086 cls: 'icon-bar navbar-toggler-icon'
4104 cls: 'collapse navbar-collapse',
4108 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4110 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4111 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4113 // tag can override this..
4115 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4118 if (this.brand !== '') {
4121 href: this.brand_href ? this.brand_href : '#',
4122 cls: 'navbar-brand',
4130 cfg.cls += ' main-nav';
4138 getHeaderChildContainer : function()
4140 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4141 return this.el.select('.navbar-header',true).first();
4144 return this.getChildContainer();
4148 initEvents : function()
4150 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4152 if (this.autohide) {
4157 Roo.get(document).on('scroll',function(e) {
4158 var ns = Roo.get(document).getScroll().top;
4159 var os = prevScroll;
4163 ft.removeClass('slideDown');
4164 ft.addClass('slideUp');
4167 ft.removeClass('slideUp');
4168 ft.addClass('slideDown');
4189 * @class Roo.bootstrap.NavSidebar
4190 * @extends Roo.bootstrap.Navbar
4191 * Bootstrap Sidebar class
4194 * Create a new Sidebar
4195 * @param {Object} config The config object
4199 Roo.bootstrap.NavSidebar = function(config){
4200 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4203 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4205 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4207 getAutoCreate : function(){
4212 cls: 'sidebar sidebar-nav'
4234 * @class Roo.bootstrap.NavGroup
4235 * @extends Roo.bootstrap.Component
4236 * Bootstrap NavGroup class
4237 * @cfg {String} align (left|right)
4238 * @cfg {Boolean} inverse
4239 * @cfg {String} type (nav|pills|tab) default nav
4240 * @cfg {String} navId - reference Id for navbar.
4244 * Create a new nav group
4245 * @param {Object} config The config object
4248 Roo.bootstrap.NavGroup = function(config){
4249 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4252 Roo.bootstrap.NavGroup.register(this);
4256 * Fires when the active item changes
4257 * @param {Roo.bootstrap.NavGroup} this
4258 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4259 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4266 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4277 getAutoCreate : function()
4279 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4286 if (['tabs','pills'].indexOf(this.type)!==-1) {
4287 cfg.cls += ' nav-' + this.type
4289 if (this.type!=='nav') {
4290 Roo.log('nav type must be nav/tabs/pills')
4292 cfg.cls += ' navbar-nav'
4295 if (this.parent() && this.parent().sidebar) {
4298 cls: 'dashboard-menu sidebar-menu'
4304 if (this.form === true) {
4310 if (this.align === 'right') {
4311 cfg.cls += ' navbar-right ml-md-auto';
4313 cfg.cls += ' navbar-left';
4317 if (this.align === 'right') {
4318 cfg.cls += ' navbar-right ml-md-auto';
4320 cfg.cls += ' mr-auto';
4324 cfg.cls += ' navbar-inverse';
4332 * sets the active Navigation item
4333 * @param {Roo.bootstrap.NavItem} the new current navitem
4335 setActiveItem : function(item)
4338 Roo.each(this.navItems, function(v){
4343 v.setActive(false, true);
4350 item.setActive(true, true);
4351 this.fireEvent('changed', this, item, prev);
4356 * gets the active Navigation item
4357 * @return {Roo.bootstrap.NavItem} the current navitem
4359 getActive : function()
4363 Roo.each(this.navItems, function(v){
4374 indexOfNav : function()
4378 Roo.each(this.navItems, function(v,i){
4389 * adds a Navigation item
4390 * @param {Roo.bootstrap.NavItem} the navitem to add
4392 addItem : function(cfg)
4394 var cn = new Roo.bootstrap.NavItem(cfg);
4396 cn.parentId = this.id;
4397 cn.onRender(this.el, null);
4401 * register a Navigation item
4402 * @param {Roo.bootstrap.NavItem} the navitem to add
4404 register : function(item)
4406 this.navItems.push( item);
4407 item.navId = this.navId;
4412 * clear all the Navigation item
4415 clearAll : function()
4418 this.el.dom.innerHTML = '';
4421 getNavItem: function(tabId)
4424 Roo.each(this.navItems, function(e) {
4425 if (e.tabId == tabId) {
4435 setActiveNext : function()
4437 var i = this.indexOfNav(this.getActive());
4438 if (i > this.navItems.length) {
4441 this.setActiveItem(this.navItems[i+1]);
4443 setActivePrev : function()
4445 var i = this.indexOfNav(this.getActive());
4449 this.setActiveItem(this.navItems[i-1]);
4451 clearWasActive : function(except) {
4452 Roo.each(this.navItems, function(e) {
4453 if (e.tabId != except.tabId && e.was_active) {
4454 e.was_active = false;
4461 getWasActive : function ()
4464 Roo.each(this.navItems, function(e) {
4479 Roo.apply(Roo.bootstrap.NavGroup, {
4483 * register a Navigation Group
4484 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4486 register : function(navgrp)
4488 this.groups[navgrp.navId] = navgrp;
4492 * fetch a Navigation Group based on the navigation ID
4493 * @param {string} the navgroup to add
4494 * @returns {Roo.bootstrap.NavGroup} the navgroup
4496 get: function(navId) {
4497 if (typeof(this.groups[navId]) == 'undefined') {
4499 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4501 return this.groups[navId] ;
4516 * @class Roo.bootstrap.NavItem
4517 * @extends Roo.bootstrap.Component
4518 * Bootstrap Navbar.NavItem class
4519 * @cfg {String} href link to
4520 * @cfg {String} html content of button
4521 * @cfg {String} badge text inside badge
4522 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4523 * @cfg {String} glyphicon name of glyphicon
4524 * @cfg {String} icon name of font awesome icon
4525 * @cfg {Boolean} active Is item active
4526 * @cfg {Boolean} disabled Is item disabled
4528 * @cfg {Boolean} preventDefault (true | false) default false
4529 * @cfg {String} tabId the tab that this item activates.
4530 * @cfg {String} tagtype (a|span) render as a href or span?
4531 * @cfg {Boolean} animateRef (true|false) link to element default false
4534 * Create a new Navbar Item
4535 * @param {Object} config The config object
4537 Roo.bootstrap.NavItem = function(config){
4538 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4543 * The raw click event for the entire grid.
4544 * @param {Roo.EventObject} e
4549 * Fires when the active item active state changes
4550 * @param {Roo.bootstrap.NavItem} this
4551 * @param {boolean} state the new state
4557 * Fires when scroll to element
4558 * @param {Roo.bootstrap.NavItem} this
4559 * @param {Object} options
4560 * @param {Roo.EventObject} e
4568 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4576 preventDefault : false,
4583 getAutoCreate : function(){
4592 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4594 if (this.disabled) {
4595 cfg.cls += ' disabled';
4598 if (this.href || this.html || this.glyphicon || this.icon) {
4602 href : this.href || "#",
4603 html: this.html || ''
4606 if (this.tagtype == 'a') {
4607 cfg.cn[0].cls = 'nav-link';
4610 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4613 if(this.glyphicon) {
4614 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4619 cfg.cn[0].html += " <span class='caret'></span>";
4623 if (this.badge !== '') {
4625 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4633 initEvents: function()
4635 if (typeof (this.menu) != 'undefined') {
4636 this.menu.parentType = this.xtype;
4637 this.menu.triggerEl = this.el;
4638 this.menu = this.addxtype(Roo.apply({}, this.menu));
4641 this.el.select('a',true).on('click', this.onClick, this);
4643 if(this.tagtype == 'span'){
4644 this.el.select('span',true).on('click', this.onClick, this);
4647 // at this point parent should be available..
4648 this.parent().register(this);
4651 onClick : function(e)
4653 if (e.getTarget('.dropdown-menu-item')) {
4654 // did you click on a menu itemm.... - then don't trigger onclick..
4659 this.preventDefault ||
4662 Roo.log("NavItem - prevent Default?");
4666 if (this.disabled) {
4670 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4671 if (tg && tg.transition) {
4672 Roo.log("waiting for the transitionend");
4678 //Roo.log("fire event clicked");
4679 if(this.fireEvent('click', this, e) === false){
4683 if(this.tagtype == 'span'){
4687 //Roo.log(this.href);
4688 var ael = this.el.select('a',true).first();
4691 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4692 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4693 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4694 return; // ignore... - it's a 'hash' to another page.
4696 Roo.log("NavItem - prevent Default?");
4698 this.scrollToElement(e);
4702 var p = this.parent();
4704 if (['tabs','pills'].indexOf(p.type)!==-1) {
4705 if (typeof(p.setActiveItem) !== 'undefined') {
4706 p.setActiveItem(this);
4710 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4711 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4712 // remove the collapsed menu expand...
4713 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4717 isActive: function () {
4720 setActive : function(state, fire, is_was_active)
4722 if (this.active && !state && this.navId) {
4723 this.was_active = true;
4724 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4726 nv.clearWasActive(this);
4730 this.active = state;
4733 this.el.removeClass('active');
4734 } else if (!this.el.hasClass('active')) {
4735 this.el.addClass('active');
4738 this.fireEvent('changed', this, state);
4741 // show a panel if it's registered and related..
4743 if (!this.navId || !this.tabId || !state || is_was_active) {
4747 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4751 var pan = tg.getPanelByName(this.tabId);
4755 // if we can not flip to new panel - go back to old nav highlight..
4756 if (false == tg.showPanel(pan)) {
4757 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4759 var onav = nv.getWasActive();
4761 onav.setActive(true, false, true);
4770 // this should not be here...
4771 setDisabled : function(state)
4773 this.disabled = state;
4775 this.el.removeClass('disabled');
4776 } else if (!this.el.hasClass('disabled')) {
4777 this.el.addClass('disabled');
4783 * Fetch the element to display the tooltip on.
4784 * @return {Roo.Element} defaults to this.el
4786 tooltipEl : function()
4788 return this.el.select('' + this.tagtype + '', true).first();
4791 scrollToElement : function(e)
4793 var c = document.body;
4796 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4798 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4799 c = document.documentElement;
4802 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4808 var o = target.calcOffsetsTo(c);
4815 this.fireEvent('scrollto', this, options, e);
4817 Roo.get(c).scrollTo('top', options.value, true);
4830 * <span> icon </span>
4831 * <span> text </span>
4832 * <span>badge </span>
4836 * @class Roo.bootstrap.NavSidebarItem
4837 * @extends Roo.bootstrap.NavItem
4838 * Bootstrap Navbar.NavSidebarItem class
4839 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4840 * {Boolean} open is the menu open
4841 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4842 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4843 * {String} buttonSize (sm|md|lg)the extra classes for the button
4844 * {Boolean} showArrow show arrow next to the text (default true)
4846 * Create a new Navbar Button
4847 * @param {Object} config The config object
4849 Roo.bootstrap.NavSidebarItem = function(config){
4850 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4855 * The raw click event for the entire grid.
4856 * @param {Roo.EventObject} e
4861 * Fires when the active item active state changes
4862 * @param {Roo.bootstrap.NavSidebarItem} this
4863 * @param {boolean} state the new state
4871 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4873 badgeWeight : 'default',
4879 buttonWeight : 'default',
4885 getAutoCreate : function(){
4890 href : this.href || '#',
4896 if(this.buttonView){
4899 href : this.href || '#',
4900 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4913 cfg.cls += ' active';
4916 if (this.disabled) {
4917 cfg.cls += ' disabled';
4920 cfg.cls += ' open x-open';
4923 if (this.glyphicon || this.icon) {
4924 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4925 a.cn.push({ tag : 'i', cls : c }) ;
4928 if(!this.buttonView){
4931 html : this.html || ''
4938 if (this.badge !== '') {
4939 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4945 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4948 a.cls += ' dropdown-toggle treeview' ;
4954 initEvents : function()
4956 if (typeof (this.menu) != 'undefined') {
4957 this.menu.parentType = this.xtype;
4958 this.menu.triggerEl = this.el;
4959 this.menu = this.addxtype(Roo.apply({}, this.menu));
4962 this.el.on('click', this.onClick, this);
4964 if(this.badge !== ''){
4965 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4970 onClick : function(e)
4977 if(this.preventDefault){
4981 this.fireEvent('click', this);
4984 disable : function()
4986 this.setDisabled(true);
4991 this.setDisabled(false);
4994 setDisabled : function(state)
4996 if(this.disabled == state){
5000 this.disabled = state;
5003 this.el.addClass('disabled');
5007 this.el.removeClass('disabled');
5012 setActive : function(state)
5014 if(this.active == state){
5018 this.active = state;
5021 this.el.addClass('active');
5025 this.el.removeClass('active');
5030 isActive: function ()
5035 setBadge : function(str)
5041 this.badgeEl.dom.innerHTML = str;
5058 * @class Roo.bootstrap.Row
5059 * @extends Roo.bootstrap.Component
5060 * Bootstrap Row class (contains columns...)
5064 * @param {Object} config The config object
5067 Roo.bootstrap.Row = function(config){
5068 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5071 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5073 getAutoCreate : function(){
5092 * @class Roo.bootstrap.Element
5093 * @extends Roo.bootstrap.Component
5094 * Bootstrap Element class
5095 * @cfg {String} html contents of the element
5096 * @cfg {String} tag tag of the element
5097 * @cfg {String} cls class of the element
5098 * @cfg {Boolean} preventDefault (true|false) default false
5099 * @cfg {Boolean} clickable (true|false) default false
5102 * Create a new Element
5103 * @param {Object} config The config object
5106 Roo.bootstrap.Element = function(config){
5107 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5113 * When a element is chick
5114 * @param {Roo.bootstrap.Element} this
5115 * @param {Roo.EventObject} e
5121 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5126 preventDefault: false,
5129 getAutoCreate : function(){
5133 // cls: this.cls, double assign in parent class Component.js :: onRender
5140 initEvents: function()
5142 Roo.bootstrap.Element.superclass.initEvents.call(this);
5145 this.el.on('click', this.onClick, this);
5150 onClick : function(e)
5152 if(this.preventDefault){
5156 this.fireEvent('click', this, e);
5159 getValue : function()
5161 return this.el.dom.innerHTML;
5164 setValue : function(value)
5166 this.el.dom.innerHTML = value;
5181 * @class Roo.bootstrap.Pagination
5182 * @extends Roo.bootstrap.Component
5183 * Bootstrap Pagination class
5184 * @cfg {String} size xs | sm | md | lg
5185 * @cfg {Boolean} inverse false | true
5188 * Create a new Pagination
5189 * @param {Object} config The config object
5192 Roo.bootstrap.Pagination = function(config){
5193 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5196 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5202 getAutoCreate : function(){
5208 cfg.cls += ' inverse';
5214 cfg.cls += " " + this.cls;
5232 * @class Roo.bootstrap.PaginationItem
5233 * @extends Roo.bootstrap.Component
5234 * Bootstrap PaginationItem class
5235 * @cfg {String} html text
5236 * @cfg {String} href the link
5237 * @cfg {Boolean} preventDefault (true | false) default true
5238 * @cfg {Boolean} active (true | false) default false
5239 * @cfg {Boolean} disabled default false
5243 * Create a new PaginationItem
5244 * @param {Object} config The config object
5248 Roo.bootstrap.PaginationItem = function(config){
5249 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5254 * The raw click event for the entire grid.
5255 * @param {Roo.EventObject} e
5261 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5265 preventDefault: true,
5270 getAutoCreate : function(){
5276 href : this.href ? this.href : '#',
5277 html : this.html ? this.html : ''
5287 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5291 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5297 initEvents: function() {
5299 this.el.on('click', this.onClick, this);
5302 onClick : function(e)
5304 Roo.log('PaginationItem on click ');
5305 if(this.preventDefault){
5313 this.fireEvent('click', this, e);
5329 * @class Roo.bootstrap.Slider
5330 * @extends Roo.bootstrap.Component
5331 * Bootstrap Slider class
5334 * Create a new Slider
5335 * @param {Object} config The config object
5338 Roo.bootstrap.Slider = function(config){
5339 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5342 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5344 getAutoCreate : function(){
5348 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5352 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5364 * Ext JS Library 1.1.1
5365 * Copyright(c) 2006-2007, Ext JS, LLC.
5367 * Originally Released Under LGPL - original licence link has changed is not relivant.
5370 * <script type="text/javascript">
5375 * @class Roo.grid.ColumnModel
5376 * @extends Roo.util.Observable
5377 * This is the default implementation of a ColumnModel used by the Grid. It defines
5378 * the columns in the grid.
5381 var colModel = new Roo.grid.ColumnModel([
5382 {header: "Ticker", width: 60, sortable: true, locked: true},
5383 {header: "Company Name", width: 150, sortable: true},
5384 {header: "Market Cap.", width: 100, sortable: true},
5385 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5386 {header: "Employees", width: 100, sortable: true, resizable: false}
5391 * The config options listed for this class are options which may appear in each
5392 * individual column definition.
5393 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5395 * @param {Object} config An Array of column config objects. See this class's
5396 * config objects for details.
5398 Roo.grid.ColumnModel = function(config){
5400 * The config passed into the constructor
5402 this.config = config;
5405 // if no id, create one
5406 // if the column does not have a dataIndex mapping,
5407 // map it to the order it is in the config
5408 for(var i = 0, len = config.length; i < len; i++){
5410 if(typeof c.dataIndex == "undefined"){
5413 if(typeof c.renderer == "string"){
5414 c.renderer = Roo.util.Format[c.renderer];
5416 if(typeof c.id == "undefined"){
5419 if(c.editor && c.editor.xtype){
5420 c.editor = Roo.factory(c.editor, Roo.grid);
5422 if(c.editor && c.editor.isFormField){
5423 c.editor = new Roo.grid.GridEditor(c.editor);
5425 this.lookup[c.id] = c;
5429 * The width of columns which have no width specified (defaults to 100)
5432 this.defaultWidth = 100;
5435 * Default sortable of columns which have no sortable specified (defaults to false)
5438 this.defaultSortable = false;
5442 * @event widthchange
5443 * Fires when the width of a column changes.
5444 * @param {ColumnModel} this
5445 * @param {Number} columnIndex The column index
5446 * @param {Number} newWidth The new width
5448 "widthchange": true,
5450 * @event headerchange
5451 * Fires when the text of a header changes.
5452 * @param {ColumnModel} this
5453 * @param {Number} columnIndex The column index
5454 * @param {Number} newText The new header text
5456 "headerchange": true,
5458 * @event hiddenchange
5459 * Fires when a column is hidden or "unhidden".
5460 * @param {ColumnModel} this
5461 * @param {Number} columnIndex The column index
5462 * @param {Boolean} hidden true if hidden, false otherwise
5464 "hiddenchange": true,
5466 * @event columnmoved
5467 * Fires when a column is moved.
5468 * @param {ColumnModel} this
5469 * @param {Number} oldIndex
5470 * @param {Number} newIndex
5472 "columnmoved" : true,
5474 * @event columlockchange
5475 * Fires when a column's locked state is changed
5476 * @param {ColumnModel} this
5477 * @param {Number} colIndex
5478 * @param {Boolean} locked true if locked
5480 "columnlockchange" : true
5482 Roo.grid.ColumnModel.superclass.constructor.call(this);
5484 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5486 * @cfg {String} header The header text to display in the Grid view.
5489 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5490 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5491 * specified, the column's index is used as an index into the Record's data Array.
5494 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5495 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5498 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5499 * Defaults to the value of the {@link #defaultSortable} property.
5500 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5503 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5506 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5509 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5512 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5515 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5516 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5517 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5518 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5521 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5524 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5527 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5530 * @cfg {String} cursor (Optional)
5533 * @cfg {String} tooltip (Optional)
5536 * @cfg {Number} xs (Optional)
5539 * @cfg {Number} sm (Optional)
5542 * @cfg {Number} md (Optional)
5545 * @cfg {Number} lg (Optional)
5548 * Returns the id of the column at the specified index.
5549 * @param {Number} index The column index
5550 * @return {String} the id
5552 getColumnId : function(index){
5553 return this.config[index].id;
5557 * Returns the column for a specified id.
5558 * @param {String} id The column id
5559 * @return {Object} the column
5561 getColumnById : function(id){
5562 return this.lookup[id];
5567 * Returns the column for a specified dataIndex.
5568 * @param {String} dataIndex The column dataIndex
5569 * @return {Object|Boolean} the column or false if not found
5571 getColumnByDataIndex: function(dataIndex){
5572 var index = this.findColumnIndex(dataIndex);
5573 return index > -1 ? this.config[index] : false;
5577 * Returns the index for a specified column id.
5578 * @param {String} id The column id
5579 * @return {Number} the index, or -1 if not found
5581 getIndexById : function(id){
5582 for(var i = 0, len = this.config.length; i < len; i++){
5583 if(this.config[i].id == id){
5591 * Returns the index for a specified column dataIndex.
5592 * @param {String} dataIndex The column dataIndex
5593 * @return {Number} the index, or -1 if not found
5596 findColumnIndex : function(dataIndex){
5597 for(var i = 0, len = this.config.length; i < len; i++){
5598 if(this.config[i].dataIndex == dataIndex){
5606 moveColumn : function(oldIndex, newIndex){
5607 var c = this.config[oldIndex];
5608 this.config.splice(oldIndex, 1);
5609 this.config.splice(newIndex, 0, c);
5610 this.dataMap = null;
5611 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5614 isLocked : function(colIndex){
5615 return this.config[colIndex].locked === true;
5618 setLocked : function(colIndex, value, suppressEvent){
5619 if(this.isLocked(colIndex) == value){
5622 this.config[colIndex].locked = value;
5624 this.fireEvent("columnlockchange", this, colIndex, value);
5628 getTotalLockedWidth : function(){
5630 for(var i = 0; i < this.config.length; i++){
5631 if(this.isLocked(i) && !this.isHidden(i)){
5632 this.totalWidth += this.getColumnWidth(i);
5638 getLockedCount : function(){
5639 for(var i = 0, len = this.config.length; i < len; i++){
5640 if(!this.isLocked(i)){
5645 return this.config.length;
5649 * Returns the number of columns.
5652 getColumnCount : function(visibleOnly){
5653 if(visibleOnly === true){
5655 for(var i = 0, len = this.config.length; i < len; i++){
5656 if(!this.isHidden(i)){
5662 return this.config.length;
5666 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5667 * @param {Function} fn
5668 * @param {Object} scope (optional)
5669 * @return {Array} result
5671 getColumnsBy : function(fn, scope){
5673 for(var i = 0, len = this.config.length; i < len; i++){
5674 var c = this.config[i];
5675 if(fn.call(scope||this, c, i) === true){
5683 * Returns true if the specified column is sortable.
5684 * @param {Number} col The column index
5687 isSortable : function(col){
5688 if(typeof this.config[col].sortable == "undefined"){
5689 return this.defaultSortable;
5691 return this.config[col].sortable;
5695 * Returns the rendering (formatting) function defined for the column.
5696 * @param {Number} col The column index.
5697 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5699 getRenderer : function(col){
5700 if(!this.config[col].renderer){
5701 return Roo.grid.ColumnModel.defaultRenderer;
5703 return this.config[col].renderer;
5707 * Sets the rendering (formatting) function for a column.
5708 * @param {Number} col The column index
5709 * @param {Function} fn The function to use to process the cell's raw data
5710 * to return HTML markup for the grid view. The render function is called with
5711 * the following parameters:<ul>
5712 * <li>Data value.</li>
5713 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5714 * <li>css A CSS style string to apply to the table cell.</li>
5715 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5716 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5717 * <li>Row index</li>
5718 * <li>Column index</li>
5719 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5721 setRenderer : function(col, fn){
5722 this.config[col].renderer = fn;
5726 * Returns the width for the specified column.
5727 * @param {Number} col The column index
5730 getColumnWidth : function(col){
5731 return this.config[col].width * 1 || this.defaultWidth;
5735 * Sets the width for a column.
5736 * @param {Number} col The column index
5737 * @param {Number} width The new width
5739 setColumnWidth : function(col, width, suppressEvent){
5740 this.config[col].width = width;
5741 this.totalWidth = null;
5743 this.fireEvent("widthchange", this, col, width);
5748 * Returns the total width of all columns.
5749 * @param {Boolean} includeHidden True to include hidden column widths
5752 getTotalWidth : function(includeHidden){
5753 if(!this.totalWidth){
5754 this.totalWidth = 0;
5755 for(var i = 0, len = this.config.length; i < len; i++){
5756 if(includeHidden || !this.isHidden(i)){
5757 this.totalWidth += this.getColumnWidth(i);
5761 return this.totalWidth;
5765 * Returns the header for the specified column.
5766 * @param {Number} col The column index
5769 getColumnHeader : function(col){
5770 return this.config[col].header;
5774 * Sets the header for a column.
5775 * @param {Number} col The column index
5776 * @param {String} header The new header
5778 setColumnHeader : function(col, header){
5779 this.config[col].header = header;
5780 this.fireEvent("headerchange", this, col, header);
5784 * Returns the tooltip for the specified column.
5785 * @param {Number} col The column index
5788 getColumnTooltip : function(col){
5789 return this.config[col].tooltip;
5792 * Sets the tooltip for a column.
5793 * @param {Number} col The column index
5794 * @param {String} tooltip The new tooltip
5796 setColumnTooltip : function(col, tooltip){
5797 this.config[col].tooltip = tooltip;
5801 * Returns the dataIndex for the specified column.
5802 * @param {Number} col The column index
5805 getDataIndex : function(col){
5806 return this.config[col].dataIndex;
5810 * Sets the dataIndex for a column.
5811 * @param {Number} col The column index
5812 * @param {Number} dataIndex The new dataIndex
5814 setDataIndex : function(col, dataIndex){
5815 this.config[col].dataIndex = dataIndex;
5821 * Returns true if the cell is editable.
5822 * @param {Number} colIndex The column index
5823 * @param {Number} rowIndex The row index - this is nto actually used..?
5826 isCellEditable : function(colIndex, rowIndex){
5827 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5831 * Returns the editor defined for the cell/column.
5832 * return false or null to disable editing.
5833 * @param {Number} colIndex The column index
5834 * @param {Number} rowIndex The row index
5837 getCellEditor : function(colIndex, rowIndex){
5838 return this.config[colIndex].editor;
5842 * Sets if a column is editable.
5843 * @param {Number} col The column index
5844 * @param {Boolean} editable True if the column is editable
5846 setEditable : function(col, editable){
5847 this.config[col].editable = editable;
5852 * Returns true if the column is hidden.
5853 * @param {Number} colIndex The column index
5856 isHidden : function(colIndex){
5857 return this.config[colIndex].hidden;
5862 * Returns true if the column width cannot be changed
5864 isFixed : function(colIndex){
5865 return this.config[colIndex].fixed;
5869 * Returns true if the column can be resized
5872 isResizable : function(colIndex){
5873 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5876 * Sets if a column is hidden.
5877 * @param {Number} colIndex The column index
5878 * @param {Boolean} hidden True if the column is hidden
5880 setHidden : function(colIndex, hidden){
5881 this.config[colIndex].hidden = hidden;
5882 this.totalWidth = null;
5883 this.fireEvent("hiddenchange", this, colIndex, hidden);
5887 * Sets the editor for a column.
5888 * @param {Number} col The column index
5889 * @param {Object} editor The editor object
5891 setEditor : function(col, editor){
5892 this.config[col].editor = editor;
5896 Roo.grid.ColumnModel.defaultRenderer = function(value)
5898 if(typeof value == "object") {
5901 if(typeof value == "string" && value.length < 1){
5905 return String.format("{0}", value);
5908 // Alias for backwards compatibility
5909 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5912 * Ext JS Library 1.1.1
5913 * Copyright(c) 2006-2007, Ext JS, LLC.
5915 * Originally Released Under LGPL - original licence link has changed is not relivant.
5918 * <script type="text/javascript">
5922 * @class Roo.LoadMask
5923 * A simple utility class for generically masking elements while loading data. If the element being masked has
5924 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5925 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5926 * element's UpdateManager load indicator and will be destroyed after the initial load.
5928 * Create a new LoadMask
5929 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5930 * @param {Object} config The config object
5932 Roo.LoadMask = function(el, config){
5933 this.el = Roo.get(el);
5934 Roo.apply(this, config);
5936 this.store.on('beforeload', this.onBeforeLoad, this);
5937 this.store.on('load', this.onLoad, this);
5938 this.store.on('loadexception', this.onLoadException, this);
5939 this.removeMask = false;
5941 var um = this.el.getUpdateManager();
5942 um.showLoadIndicator = false; // disable the default indicator
5943 um.on('beforeupdate', this.onBeforeLoad, this);
5944 um.on('update', this.onLoad, this);
5945 um.on('failure', this.onLoad, this);
5946 this.removeMask = true;
5950 Roo.LoadMask.prototype = {
5952 * @cfg {Boolean} removeMask
5953 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5954 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5958 * The text to display in a centered loading message box (defaults to 'Loading...')
5962 * @cfg {String} msgCls
5963 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5965 msgCls : 'x-mask-loading',
5968 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5974 * Disables the mask to prevent it from being displayed
5976 disable : function(){
5977 this.disabled = true;
5981 * Enables the mask so that it can be displayed
5983 enable : function(){
5984 this.disabled = false;
5987 onLoadException : function()
5991 if (typeof(arguments[3]) != 'undefined') {
5992 Roo.MessageBox.alert("Error loading",arguments[3]);
5996 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5997 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6004 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6009 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6013 onBeforeLoad : function(){
6015 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6020 destroy : function(){
6022 this.store.un('beforeload', this.onBeforeLoad, this);
6023 this.store.un('load', this.onLoad, this);
6024 this.store.un('loadexception', this.onLoadException, this);
6026 var um = this.el.getUpdateManager();
6027 um.un('beforeupdate', this.onBeforeLoad, this);
6028 um.un('update', this.onLoad, this);
6029 um.un('failure', this.onLoad, this);
6040 * @class Roo.bootstrap.Table
6041 * @extends Roo.bootstrap.Component
6042 * Bootstrap Table class
6043 * @cfg {String} cls table class
6044 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6045 * @cfg {String} bgcolor Specifies the background color for a table
6046 * @cfg {Number} border Specifies whether the table cells should have borders or not
6047 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6048 * @cfg {Number} cellspacing Specifies the space between cells
6049 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6050 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6051 * @cfg {String} sortable Specifies that the table should be sortable
6052 * @cfg {String} summary Specifies a summary of the content of a table
6053 * @cfg {Number} width Specifies the width of a table
6054 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6056 * @cfg {boolean} striped Should the rows be alternative striped
6057 * @cfg {boolean} bordered Add borders to the table
6058 * @cfg {boolean} hover Add hover highlighting
6059 * @cfg {boolean} condensed Format condensed
6060 * @cfg {boolean} responsive Format condensed
6061 * @cfg {Boolean} loadMask (true|false) default false
6062 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6063 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6064 * @cfg {Boolean} rowSelection (true|false) default false
6065 * @cfg {Boolean} cellSelection (true|false) default false
6066 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6067 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6068 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6069 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6073 * Create a new Table
6074 * @param {Object} config The config object
6077 Roo.bootstrap.Table = function(config){
6078 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6083 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6084 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6085 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6086 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6088 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6090 this.sm.grid = this;
6091 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6092 this.sm = this.selModel;
6093 this.sm.xmodule = this.xmodule || false;
6096 if (this.cm && typeof(this.cm.config) == 'undefined') {
6097 this.colModel = new Roo.grid.ColumnModel(this.cm);
6098 this.cm = this.colModel;
6099 this.cm.xmodule = this.xmodule || false;
6102 this.store= Roo.factory(this.store, Roo.data);
6103 this.ds = this.store;
6104 this.ds.xmodule = this.xmodule || false;
6107 if (this.footer && this.store) {
6108 this.footer.dataSource = this.ds;
6109 this.footer = Roo.factory(this.footer);
6116 * Fires when a cell is clicked
6117 * @param {Roo.bootstrap.Table} this
6118 * @param {Roo.Element} el
6119 * @param {Number} rowIndex
6120 * @param {Number} columnIndex
6121 * @param {Roo.EventObject} e
6125 * @event celldblclick
6126 * Fires when a cell is double clicked
6127 * @param {Roo.bootstrap.Table} this
6128 * @param {Roo.Element} el
6129 * @param {Number} rowIndex
6130 * @param {Number} columnIndex
6131 * @param {Roo.EventObject} e
6133 "celldblclick" : true,
6136 * Fires when a row is clicked
6137 * @param {Roo.bootstrap.Table} this
6138 * @param {Roo.Element} el
6139 * @param {Number} rowIndex
6140 * @param {Roo.EventObject} e
6144 * @event rowdblclick
6145 * Fires when a row is double clicked
6146 * @param {Roo.bootstrap.Table} this
6147 * @param {Roo.Element} el
6148 * @param {Number} rowIndex
6149 * @param {Roo.EventObject} e
6151 "rowdblclick" : true,
6154 * Fires when a mouseover occur
6155 * @param {Roo.bootstrap.Table} this
6156 * @param {Roo.Element} el
6157 * @param {Number} rowIndex
6158 * @param {Number} columnIndex
6159 * @param {Roo.EventObject} e
6164 * Fires when a mouseout occur
6165 * @param {Roo.bootstrap.Table} this
6166 * @param {Roo.Element} el
6167 * @param {Number} rowIndex
6168 * @param {Number} columnIndex
6169 * @param {Roo.EventObject} e
6174 * Fires when a row is rendered, so you can change add a style to it.
6175 * @param {Roo.bootstrap.Table} this
6176 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6180 * @event rowsrendered
6181 * Fires when all the rows have been rendered
6182 * @param {Roo.bootstrap.Table} this
6184 'rowsrendered' : true,
6186 * @event contextmenu
6187 * The raw contextmenu event for the entire grid.
6188 * @param {Roo.EventObject} e
6190 "contextmenu" : true,
6192 * @event rowcontextmenu
6193 * Fires when a row is right clicked
6194 * @param {Roo.bootstrap.Table} this
6195 * @param {Number} rowIndex
6196 * @param {Roo.EventObject} e
6198 "rowcontextmenu" : true,
6200 * @event cellcontextmenu
6201 * Fires when a cell is right clicked
6202 * @param {Roo.bootstrap.Table} this
6203 * @param {Number} rowIndex
6204 * @param {Number} cellIndex
6205 * @param {Roo.EventObject} e
6207 "cellcontextmenu" : true,
6209 * @event headercontextmenu
6210 * Fires when a header is right clicked
6211 * @param {Roo.bootstrap.Table} this
6212 * @param {Number} columnIndex
6213 * @param {Roo.EventObject} e
6215 "headercontextmenu" : true
6219 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6245 rowSelection : false,
6246 cellSelection : false,
6249 // Roo.Element - the tbody
6251 // Roo.Element - thead element
6254 container: false, // used by gridpanel...
6260 auto_hide_footer : false,
6262 getAutoCreate : function()
6264 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6271 if (this.scrollBody) {
6272 cfg.cls += ' table-body-fixed';
6275 cfg.cls += ' table-striped';
6279 cfg.cls += ' table-hover';
6281 if (this.bordered) {
6282 cfg.cls += ' table-bordered';
6284 if (this.condensed) {
6285 cfg.cls += ' table-condensed';
6287 if (this.responsive) {
6288 cfg.cls += ' table-responsive';
6292 cfg.cls+= ' ' +this.cls;
6295 // this lot should be simplifed...
6308 ].forEach(function(k) {
6316 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6319 if(this.store || this.cm){
6320 if(this.headerShow){
6321 cfg.cn.push(this.renderHeader());
6324 cfg.cn.push(this.renderBody());
6326 if(this.footerShow){
6327 cfg.cn.push(this.renderFooter());
6329 // where does this come from?
6330 //cfg.cls+= ' TableGrid';
6333 return { cn : [ cfg ] };
6336 initEvents : function()
6338 if(!this.store || !this.cm){
6341 if (this.selModel) {
6342 this.selModel.initEvents();
6346 //Roo.log('initEvents with ds!!!!');
6348 this.mainBody = this.el.select('tbody', true).first();
6349 this.mainHead = this.el.select('thead', true).first();
6350 this.mainFoot = this.el.select('tfoot', true).first();
6356 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6357 e.on('click', _this.sort, _this);
6360 this.mainBody.on("click", this.onClick, this);
6361 this.mainBody.on("dblclick", this.onDblClick, this);
6363 // why is this done????? = it breaks dialogs??
6364 //this.parent().el.setStyle('position', 'relative');
6368 this.footer.parentId = this.id;
6369 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6372 this.el.select('tfoot tr td').first().addClass('hide');
6377 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6380 this.store.on('load', this.onLoad, this);
6381 this.store.on('beforeload', this.onBeforeLoad, this);
6382 this.store.on('update', this.onUpdate, this);
6383 this.store.on('add', this.onAdd, this);
6384 this.store.on("clear", this.clear, this);
6386 this.el.on("contextmenu", this.onContextMenu, this);
6388 this.mainBody.on('scroll', this.onBodyScroll, this);
6390 this.cm.on("headerchange", this.onHeaderChange, this);
6392 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6396 onContextMenu : function(e, t)
6398 this.processEvent("contextmenu", e);
6401 processEvent : function(name, e)
6403 if (name != 'touchstart' ) {
6404 this.fireEvent(name, e);
6407 var t = e.getTarget();
6409 var cell = Roo.get(t);
6415 if(cell.findParent('tfoot', false, true)){
6419 if(cell.findParent('thead', false, true)){
6421 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6422 cell = Roo.get(t).findParent('th', false, true);
6424 Roo.log("failed to find th in thead?");
6425 Roo.log(e.getTarget());
6430 var cellIndex = cell.dom.cellIndex;
6432 var ename = name == 'touchstart' ? 'click' : name;
6433 this.fireEvent("header" + ename, this, cellIndex, e);
6438 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6439 cell = Roo.get(t).findParent('td', false, true);
6441 Roo.log("failed to find th in tbody?");
6442 Roo.log(e.getTarget());
6447 var row = cell.findParent('tr', false, true);
6448 var cellIndex = cell.dom.cellIndex;
6449 var rowIndex = row.dom.rowIndex - 1;
6453 this.fireEvent("row" + name, this, rowIndex, e);
6457 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6463 onMouseover : function(e, el)
6465 var cell = Roo.get(el);
6471 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6472 cell = cell.findParent('td', false, true);
6475 var row = cell.findParent('tr', false, true);
6476 var cellIndex = cell.dom.cellIndex;
6477 var rowIndex = row.dom.rowIndex - 1; // start from 0
6479 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6483 onMouseout : function(e, el)
6485 var cell = Roo.get(el);
6491 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6492 cell = cell.findParent('td', false, true);
6495 var row = cell.findParent('tr', false, true);
6496 var cellIndex = cell.dom.cellIndex;
6497 var rowIndex = row.dom.rowIndex - 1; // start from 0
6499 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6503 onClick : function(e, el)
6505 var cell = Roo.get(el);
6507 if(!cell || (!this.cellSelection && !this.rowSelection)){
6511 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6512 cell = cell.findParent('td', false, true);
6515 if(!cell || typeof(cell) == 'undefined'){
6519 var row = cell.findParent('tr', false, true);
6521 if(!row || typeof(row) == 'undefined'){
6525 var cellIndex = cell.dom.cellIndex;
6526 var rowIndex = this.getRowIndex(row);
6528 // why??? - should these not be based on SelectionModel?
6529 if(this.cellSelection){
6530 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6533 if(this.rowSelection){
6534 this.fireEvent('rowclick', this, row, rowIndex, e);
6540 onDblClick : function(e,el)
6542 var cell = Roo.get(el);
6544 if(!cell || (!this.cellSelection && !this.rowSelection)){
6548 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6549 cell = cell.findParent('td', false, true);
6552 if(!cell || typeof(cell) == 'undefined'){
6556 var row = cell.findParent('tr', false, true);
6558 if(!row || typeof(row) == 'undefined'){
6562 var cellIndex = cell.dom.cellIndex;
6563 var rowIndex = this.getRowIndex(row);
6565 if(this.cellSelection){
6566 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6569 if(this.rowSelection){
6570 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6574 sort : function(e,el)
6576 var col = Roo.get(el);
6578 if(!col.hasClass('sortable')){
6582 var sort = col.attr('sort');
6585 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6589 this.store.sortInfo = {field : sort, direction : dir};
6592 Roo.log("calling footer first");
6593 this.footer.onClick('first');
6596 this.store.load({ params : { start : 0 } });
6600 renderHeader : function()
6608 this.totalWidth = 0;
6610 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6612 var config = cm.config[i];
6616 cls : 'x-hcol-' + i,
6618 html: cm.getColumnHeader(i)
6623 if(typeof(config.sortable) != 'undefined' && config.sortable){
6625 c.html = '<i class="glyphicon"></i>' + c.html;
6628 if(typeof(config.lgHeader) != 'undefined'){
6629 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6632 if(typeof(config.mdHeader) != 'undefined'){
6633 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6636 if(typeof(config.smHeader) != 'undefined'){
6637 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6640 if(typeof(config.xsHeader) != 'undefined'){
6641 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6648 if(typeof(config.tooltip) != 'undefined'){
6649 c.tooltip = config.tooltip;
6652 if(typeof(config.colspan) != 'undefined'){
6653 c.colspan = config.colspan;
6656 if(typeof(config.hidden) != 'undefined' && config.hidden){
6657 c.style += ' display:none;';
6660 if(typeof(config.dataIndex) != 'undefined'){
6661 c.sort = config.dataIndex;
6666 if(typeof(config.align) != 'undefined' && config.align.length){
6667 c.style += ' text-align:' + config.align + ';';
6670 if(typeof(config.width) != 'undefined'){
6671 c.style += ' width:' + config.width + 'px;';
6672 this.totalWidth += config.width;
6674 this.totalWidth += 100; // assume minimum of 100 per column?
6677 if(typeof(config.cls) != 'undefined'){
6678 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6681 ['xs','sm','md','lg'].map(function(size){
6683 if(typeof(config[size]) == 'undefined'){
6687 if (!config[size]) { // 0 = hidden
6688 c.cls += ' hidden-' + size;
6692 c.cls += ' col-' + size + '-' + config[size];
6702 renderBody : function()
6712 colspan : this.cm.getColumnCount()
6722 renderFooter : function()
6732 colspan : this.cm.getColumnCount()
6746 // Roo.log('ds onload');
6751 var ds = this.store;
6753 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6754 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6755 if (_this.store.sortInfo) {
6757 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6758 e.select('i', true).addClass(['glyphicon-arrow-up']);
6761 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6762 e.select('i', true).addClass(['glyphicon-arrow-down']);
6767 var tbody = this.mainBody;
6769 if(ds.getCount() > 0){
6770 ds.data.each(function(d,rowIndex){
6771 var row = this.renderRow(cm, ds, rowIndex);
6773 tbody.createChild(row);
6777 if(row.cellObjects.length){
6778 Roo.each(row.cellObjects, function(r){
6779 _this.renderCellObject(r);
6786 var tfoot = this.el.select('tfoot', true).first();
6788 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6790 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6792 var total = this.ds.getTotalCount();
6794 if(this.footer.pageSize < total){
6795 this.mainFoot.show();
6799 Roo.each(this.el.select('tbody td', true).elements, function(e){
6800 e.on('mouseover', _this.onMouseover, _this);
6803 Roo.each(this.el.select('tbody td', true).elements, function(e){
6804 e.on('mouseout', _this.onMouseout, _this);
6806 this.fireEvent('rowsrendered', this);
6812 onUpdate : function(ds,record)
6814 this.refreshRow(record);
6818 onRemove : function(ds, record, index, isUpdate){
6819 if(isUpdate !== true){
6820 this.fireEvent("beforerowremoved", this, index, record);
6822 var bt = this.mainBody.dom;
6824 var rows = this.el.select('tbody > tr', true).elements;
6826 if(typeof(rows[index]) != 'undefined'){
6827 bt.removeChild(rows[index].dom);
6830 // if(bt.rows[index]){
6831 // bt.removeChild(bt.rows[index]);
6834 if(isUpdate !== true){
6835 //this.stripeRows(index);
6836 //this.syncRowHeights(index, index);
6838 this.fireEvent("rowremoved", this, index, record);
6842 onAdd : function(ds, records, rowIndex)
6844 //Roo.log('on Add called');
6845 // - note this does not handle multiple adding very well..
6846 var bt = this.mainBody.dom;
6847 for (var i =0 ; i < records.length;i++) {
6848 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6849 //Roo.log(records[i]);
6850 //Roo.log(this.store.getAt(rowIndex+i));
6851 this.insertRow(this.store, rowIndex + i, false);
6858 refreshRow : function(record){
6859 var ds = this.store, index;
6860 if(typeof record == 'number'){
6862 record = ds.getAt(index);
6864 index = ds.indexOf(record);
6866 this.insertRow(ds, index, true);
6868 this.onRemove(ds, record, index+1, true);
6870 //this.syncRowHeights(index, index);
6872 this.fireEvent("rowupdated", this, index, record);
6875 insertRow : function(dm, rowIndex, isUpdate){
6878 this.fireEvent("beforerowsinserted", this, rowIndex);
6880 //var s = this.getScrollState();
6881 var row = this.renderRow(this.cm, this.store, rowIndex);
6882 // insert before rowIndex..
6883 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6887 if(row.cellObjects.length){
6888 Roo.each(row.cellObjects, function(r){
6889 _this.renderCellObject(r);
6894 this.fireEvent("rowsinserted", this, rowIndex);
6895 //this.syncRowHeights(firstRow, lastRow);
6896 //this.stripeRows(firstRow);
6903 getRowDom : function(rowIndex)
6905 var rows = this.el.select('tbody > tr', true).elements;
6907 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6910 // returns the object tree for a tr..
6913 renderRow : function(cm, ds, rowIndex)
6915 var d = ds.getAt(rowIndex);
6919 cls : 'x-row-' + rowIndex,
6923 var cellObjects = [];
6925 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6926 var config = cm.config[i];
6928 var renderer = cm.getRenderer(i);
6932 if(typeof(renderer) !== 'undefined'){
6933 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6935 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6936 // and are rendered into the cells after the row is rendered - using the id for the element.
6938 if(typeof(value) === 'object'){
6948 rowIndex : rowIndex,
6953 this.fireEvent('rowclass', this, rowcfg);
6957 cls : rowcfg.rowClass + ' x-col-' + i,
6959 html: (typeof(value) === 'object') ? '' : value
6966 if(typeof(config.colspan) != 'undefined'){
6967 td.colspan = config.colspan;
6970 if(typeof(config.hidden) != 'undefined' && config.hidden){
6971 td.style += ' display:none;';
6974 if(typeof(config.align) != 'undefined' && config.align.length){
6975 td.style += ' text-align:' + config.align + ';';
6977 if(typeof(config.valign) != 'undefined' && config.valign.length){
6978 td.style += ' vertical-align:' + config.valign + ';';
6981 if(typeof(config.width) != 'undefined'){
6982 td.style += ' width:' + config.width + 'px;';
6985 if(typeof(config.cursor) != 'undefined'){
6986 td.style += ' cursor:' + config.cursor + ';';
6989 if(typeof(config.cls) != 'undefined'){
6990 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6993 ['xs','sm','md','lg'].map(function(size){
6995 if(typeof(config[size]) == 'undefined'){
6999 if (!config[size]) { // 0 = hidden
7000 td.cls += ' hidden-' + size;
7004 td.cls += ' col-' + size + '-' + config[size];
7012 row.cellObjects = cellObjects;
7020 onBeforeLoad : function()
7029 this.el.select('tbody', true).first().dom.innerHTML = '';
7032 * Show or hide a row.
7033 * @param {Number} rowIndex to show or hide
7034 * @param {Boolean} state hide
7036 setRowVisibility : function(rowIndex, state)
7038 var bt = this.mainBody.dom;
7040 var rows = this.el.select('tbody > tr', true).elements;
7042 if(typeof(rows[rowIndex]) == 'undefined'){
7045 rows[rowIndex].dom.style.display = state ? '' : 'none';
7049 getSelectionModel : function(){
7051 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7053 return this.selModel;
7056 * Render the Roo.bootstrap object from renderder
7058 renderCellObject : function(r)
7062 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7064 var t = r.cfg.render(r.container);
7067 Roo.each(r.cfg.cn, function(c){
7069 container: t.getChildContainer(),
7072 _this.renderCellObject(child);
7077 getRowIndex : function(row)
7081 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7092 * Returns the grid's underlying element = used by panel.Grid
7093 * @return {Element} The element
7095 getGridEl : function(){
7099 * Forces a resize - used by panel.Grid
7100 * @return {Element} The element
7102 autoSize : function()
7104 //var ctr = Roo.get(this.container.dom.parentElement);
7105 var ctr = Roo.get(this.el.dom);
7107 var thd = this.getGridEl().select('thead',true).first();
7108 var tbd = this.getGridEl().select('tbody', true).first();
7109 var tfd = this.getGridEl().select('tfoot', true).first();
7111 var cw = ctr.getWidth();
7115 tbd.setSize(ctr.getWidth(),
7116 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7118 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7121 cw = Math.max(cw, this.totalWidth);
7122 this.getGridEl().select('tr',true).setWidth(cw);
7123 // resize 'expandable coloumn?
7125 return; // we doe not have a view in this design..
7128 onBodyScroll: function()
7130 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7132 this.mainHead.setStyle({
7133 'position' : 'relative',
7134 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7140 var scrollHeight = this.mainBody.dom.scrollHeight;
7142 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7144 var height = this.mainBody.getHeight();
7146 if(scrollHeight - height == scrollTop) {
7148 var total = this.ds.getTotalCount();
7150 if(this.footer.cursor + this.footer.pageSize < total){
7152 this.footer.ds.load({
7154 start : this.footer.cursor + this.footer.pageSize,
7155 limit : this.footer.pageSize
7165 onHeaderChange : function()
7167 var header = this.renderHeader();
7168 var table = this.el.select('table', true).first();
7170 this.mainHead.remove();
7171 this.mainHead = table.createChild(header, this.mainBody, false);
7174 onHiddenChange : function(colModel, colIndex, hidden)
7176 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7177 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7179 this.CSS.updateRule(thSelector, "display", "");
7180 this.CSS.updateRule(tdSelector, "display", "");
7183 this.CSS.updateRule(thSelector, "display", "none");
7184 this.CSS.updateRule(tdSelector, "display", "none");
7187 this.onHeaderChange();
7191 setColumnWidth: function(col_index, width)
7193 // width = "md-2 xs-2..."
7194 if(!this.colModel.config[col_index]) {
7198 var w = width.split(" ");
7200 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7202 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7205 for(var j = 0; j < w.length; j++) {
7211 var size_cls = w[j].split("-");
7213 if(!Number.isInteger(size_cls[1] * 1)) {
7217 if(!this.colModel.config[col_index][size_cls[0]]) {
7221 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7225 h_row[0].classList.replace(
7226 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7227 "col-"+size_cls[0]+"-"+size_cls[1]
7230 for(var i = 0; i < rows.length; i++) {
7232 var size_cls = w[j].split("-");
7234 if(!Number.isInteger(size_cls[1] * 1)) {
7238 if(!this.colModel.config[col_index][size_cls[0]]) {
7242 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7246 rows[i].classList.replace(
7247 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7248 "col-"+size_cls[0]+"-"+size_cls[1]
7252 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7267 * @class Roo.bootstrap.TableCell
7268 * @extends Roo.bootstrap.Component
7269 * Bootstrap TableCell class
7270 * @cfg {String} html cell contain text
7271 * @cfg {String} cls cell class
7272 * @cfg {String} tag cell tag (td|th) default td
7273 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7274 * @cfg {String} align Aligns the content in a cell
7275 * @cfg {String} axis Categorizes cells
7276 * @cfg {String} bgcolor Specifies the background color of a cell
7277 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7278 * @cfg {Number} colspan Specifies the number of columns a cell should span
7279 * @cfg {String} headers Specifies one or more header cells a cell is related to
7280 * @cfg {Number} height Sets the height of a cell
7281 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7282 * @cfg {Number} rowspan Sets the number of rows a cell should span
7283 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7284 * @cfg {String} valign Vertical aligns the content in a cell
7285 * @cfg {Number} width Specifies the width of a cell
7288 * Create a new TableCell
7289 * @param {Object} config The config object
7292 Roo.bootstrap.TableCell = function(config){
7293 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7296 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7316 getAutoCreate : function(){
7317 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7337 cfg.align=this.align
7343 cfg.bgcolor=this.bgcolor
7346 cfg.charoff=this.charoff
7349 cfg.colspan=this.colspan
7352 cfg.headers=this.headers
7355 cfg.height=this.height
7358 cfg.nowrap=this.nowrap
7361 cfg.rowspan=this.rowspan
7364 cfg.scope=this.scope
7367 cfg.valign=this.valign
7370 cfg.width=this.width
7389 * @class Roo.bootstrap.TableRow
7390 * @extends Roo.bootstrap.Component
7391 * Bootstrap TableRow class
7392 * @cfg {String} cls row class
7393 * @cfg {String} align Aligns the content in a table row
7394 * @cfg {String} bgcolor Specifies a background color for a table row
7395 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7396 * @cfg {String} valign Vertical aligns the content in a table row
7399 * Create a new TableRow
7400 * @param {Object} config The config object
7403 Roo.bootstrap.TableRow = function(config){
7404 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7407 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7415 getAutoCreate : function(){
7416 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7426 cfg.align = this.align;
7429 cfg.bgcolor = this.bgcolor;
7432 cfg.charoff = this.charoff;
7435 cfg.valign = this.valign;
7453 * @class Roo.bootstrap.TableBody
7454 * @extends Roo.bootstrap.Component
7455 * Bootstrap TableBody class
7456 * @cfg {String} cls element class
7457 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7458 * @cfg {String} align Aligns the content inside the element
7459 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7460 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7463 * Create a new TableBody
7464 * @param {Object} config The config object
7467 Roo.bootstrap.TableBody = function(config){
7468 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7471 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7479 getAutoCreate : function(){
7480 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7494 cfg.align = this.align;
7497 cfg.charoff = this.charoff;
7500 cfg.valign = this.valign;
7507 // initEvents : function()
7514 // this.store = Roo.factory(this.store, Roo.data);
7515 // this.store.on('load', this.onLoad, this);
7517 // this.store.load();
7521 // onLoad: function ()
7523 // this.fireEvent('load', this);
7533 * Ext JS Library 1.1.1
7534 * Copyright(c) 2006-2007, Ext JS, LLC.
7536 * Originally Released Under LGPL - original licence link has changed is not relivant.
7539 * <script type="text/javascript">
7542 // as we use this in bootstrap.
7543 Roo.namespace('Roo.form');
7545 * @class Roo.form.Action
7546 * Internal Class used to handle form actions
7548 * @param {Roo.form.BasicForm} el The form element or its id
7549 * @param {Object} config Configuration options
7554 // define the action interface
7555 Roo.form.Action = function(form, options){
7557 this.options = options || {};
7560 * Client Validation Failed
7563 Roo.form.Action.CLIENT_INVALID = 'client';
7565 * Server Validation Failed
7568 Roo.form.Action.SERVER_INVALID = 'server';
7570 * Connect to Server Failed
7573 Roo.form.Action.CONNECT_FAILURE = 'connect';
7575 * Reading Data from Server Failed
7578 Roo.form.Action.LOAD_FAILURE = 'load';
7580 Roo.form.Action.prototype = {
7582 failureType : undefined,
7583 response : undefined,
7587 run : function(options){
7592 success : function(response){
7597 handleResponse : function(response){
7601 // default connection failure
7602 failure : function(response){
7604 this.response = response;
7605 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7606 this.form.afterAction(this, false);
7609 processResponse : function(response){
7610 this.response = response;
7611 if(!response.responseText){
7614 this.result = this.handleResponse(response);
7618 // utility functions used internally
7619 getUrl : function(appendParams){
7620 var url = this.options.url || this.form.url || this.form.el.dom.action;
7622 var p = this.getParams();
7624 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7630 getMethod : function(){
7631 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7634 getParams : function(){
7635 var bp = this.form.baseParams;
7636 var p = this.options.params;
7638 if(typeof p == "object"){
7639 p = Roo.urlEncode(Roo.applyIf(p, bp));
7640 }else if(typeof p == 'string' && bp){
7641 p += '&' + Roo.urlEncode(bp);
7644 p = Roo.urlEncode(bp);
7649 createCallback : function(){
7651 success: this.success,
7652 failure: this.failure,
7654 timeout: (this.form.timeout*1000),
7655 upload: this.form.fileUpload ? this.success : undefined
7660 Roo.form.Action.Submit = function(form, options){
7661 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7664 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7667 haveProgress : false,
7668 uploadComplete : false,
7670 // uploadProgress indicator.
7671 uploadProgress : function()
7673 if (!this.form.progressUrl) {
7677 if (!this.haveProgress) {
7678 Roo.MessageBox.progress("Uploading", "Uploading");
7680 if (this.uploadComplete) {
7681 Roo.MessageBox.hide();
7685 this.haveProgress = true;
7687 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7689 var c = new Roo.data.Connection();
7691 url : this.form.progressUrl,
7696 success : function(req){
7697 //console.log(data);
7701 rdata = Roo.decode(req.responseText)
7703 Roo.log("Invalid data from server..");
7707 if (!rdata || !rdata.success) {
7709 Roo.MessageBox.alert(Roo.encode(rdata));
7712 var data = rdata.data;
7714 if (this.uploadComplete) {
7715 Roo.MessageBox.hide();
7720 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7721 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7724 this.uploadProgress.defer(2000,this);
7727 failure: function(data) {
7728 Roo.log('progress url failed ');
7739 // run get Values on the form, so it syncs any secondary forms.
7740 this.form.getValues();
7742 var o = this.options;
7743 var method = this.getMethod();
7744 var isPost = method == 'POST';
7745 if(o.clientValidation === false || this.form.isValid()){
7747 if (this.form.progressUrl) {
7748 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7749 (new Date() * 1) + '' + Math.random());
7754 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7755 form:this.form.el.dom,
7756 url:this.getUrl(!isPost),
7758 params:isPost ? this.getParams() : null,
7759 isUpload: this.form.fileUpload
7762 this.uploadProgress();
7764 }else if (o.clientValidation !== false){ // client validation failed
7765 this.failureType = Roo.form.Action.CLIENT_INVALID;
7766 this.form.afterAction(this, false);
7770 success : function(response)
7772 this.uploadComplete= true;
7773 if (this.haveProgress) {
7774 Roo.MessageBox.hide();
7778 var result = this.processResponse(response);
7779 if(result === true || result.success){
7780 this.form.afterAction(this, true);
7784 this.form.markInvalid(result.errors);
7785 this.failureType = Roo.form.Action.SERVER_INVALID;
7787 this.form.afterAction(this, false);
7789 failure : function(response)
7791 this.uploadComplete= true;
7792 if (this.haveProgress) {
7793 Roo.MessageBox.hide();
7796 this.response = response;
7797 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7798 this.form.afterAction(this, false);
7801 handleResponse : function(response){
7802 if(this.form.errorReader){
7803 var rs = this.form.errorReader.read(response);
7806 for(var i = 0, len = rs.records.length; i < len; i++) {
7807 var r = rs.records[i];
7811 if(errors.length < 1){
7815 success : rs.success,
7821 ret = Roo.decode(response.responseText);
7825 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7835 Roo.form.Action.Load = function(form, options){
7836 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7837 this.reader = this.form.reader;
7840 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7845 Roo.Ajax.request(Roo.apply(
7846 this.createCallback(), {
7847 method:this.getMethod(),
7848 url:this.getUrl(false),
7849 params:this.getParams()
7853 success : function(response){
7855 var result = this.processResponse(response);
7856 if(result === true || !result.success || !result.data){
7857 this.failureType = Roo.form.Action.LOAD_FAILURE;
7858 this.form.afterAction(this, false);
7861 this.form.clearInvalid();
7862 this.form.setValues(result.data);
7863 this.form.afterAction(this, true);
7866 handleResponse : function(response){
7867 if(this.form.reader){
7868 var rs = this.form.reader.read(response);
7869 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7871 success : rs.success,
7875 return Roo.decode(response.responseText);
7879 Roo.form.Action.ACTION_TYPES = {
7880 'load' : Roo.form.Action.Load,
7881 'submit' : Roo.form.Action.Submit
7890 * @class Roo.bootstrap.Form
7891 * @extends Roo.bootstrap.Component
7892 * Bootstrap Form class
7893 * @cfg {String} method GET | POST (default POST)
7894 * @cfg {String} labelAlign top | left (default top)
7895 * @cfg {String} align left | right - for navbars
7896 * @cfg {Boolean} loadMask load mask when submit (default true)
7901 * @param {Object} config The config object
7905 Roo.bootstrap.Form = function(config){
7907 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7909 Roo.bootstrap.Form.popover.apply();
7913 * @event clientvalidation
7914 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7915 * @param {Form} this
7916 * @param {Boolean} valid true if the form has passed client-side validation
7918 clientvalidation: true,
7920 * @event beforeaction
7921 * Fires before any action is performed. Return false to cancel the action.
7922 * @param {Form} this
7923 * @param {Action} action The action to be performed
7927 * @event actionfailed
7928 * Fires when an action fails.
7929 * @param {Form} this
7930 * @param {Action} action The action that failed
7932 actionfailed : true,
7934 * @event actioncomplete
7935 * Fires when an action is completed.
7936 * @param {Form} this
7937 * @param {Action} action The action that completed
7939 actioncomplete : true
7943 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7946 * @cfg {String} method
7947 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7952 * The URL to use for form actions if one isn't supplied in the action options.
7955 * @cfg {Boolean} fileUpload
7956 * Set to true if this form is a file upload.
7960 * @cfg {Object} baseParams
7961 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7965 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7969 * @cfg {Sting} align (left|right) for navbar forms
7974 activeAction : null,
7977 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7978 * element by passing it or its id or mask the form itself by passing in true.
7981 waitMsgTarget : false,
7986 * @cfg {Boolean} errorMask (true|false) default false
7991 * @cfg {Number} maskOffset Default 100
7996 * @cfg {Boolean} maskBody
8000 getAutoCreate : function(){
8004 method : this.method || 'POST',
8005 id : this.id || Roo.id(),
8008 if (this.parent().xtype.match(/^Nav/)) {
8009 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8013 if (this.labelAlign == 'left' ) {
8014 cfg.cls += ' form-horizontal';
8020 initEvents : function()
8022 this.el.on('submit', this.onSubmit, this);
8023 // this was added as random key presses on the form where triggering form submit.
8024 this.el.on('keypress', function(e) {
8025 if (e.getCharCode() != 13) {
8028 // we might need to allow it for textareas.. and some other items.
8029 // check e.getTarget().
8031 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8035 Roo.log("keypress blocked");
8043 onSubmit : function(e){
8048 * Returns true if client-side validation on the form is successful.
8051 isValid : function(){
8052 var items = this.getItems();
8056 items.each(function(f){
8062 Roo.log('invalid field: ' + f.name);
8066 if(!target && f.el.isVisible(true)){
8072 if(this.errorMask && !valid){
8073 Roo.bootstrap.Form.popover.mask(this, target);
8080 * Returns true if any fields in this form have changed since their original load.
8083 isDirty : function(){
8085 var items = this.getItems();
8086 items.each(function(f){
8096 * Performs a predefined action (submit or load) or custom actions you define on this form.
8097 * @param {String} actionName The name of the action type
8098 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8099 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8100 * accept other config options):
8102 Property Type Description
8103 ---------------- --------------- ----------------------------------------------------------------------------------
8104 url String The url for the action (defaults to the form's url)
8105 method String The form method to use (defaults to the form's method, or POST if not defined)
8106 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8107 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8108 validate the form on the client (defaults to false)
8110 * @return {BasicForm} this
8112 doAction : function(action, options){
8113 if(typeof action == 'string'){
8114 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8116 if(this.fireEvent('beforeaction', this, action) !== false){
8117 this.beforeAction(action);
8118 action.run.defer(100, action);
8124 beforeAction : function(action){
8125 var o = action.options;
8130 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8132 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8135 // not really supported yet.. ??
8137 //if(this.waitMsgTarget === true){
8138 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8139 //}else if(this.waitMsgTarget){
8140 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8141 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8143 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8149 afterAction : function(action, success){
8150 this.activeAction = null;
8151 var o = action.options;
8156 Roo.get(document.body).unmask();
8162 //if(this.waitMsgTarget === true){
8163 // this.el.unmask();
8164 //}else if(this.waitMsgTarget){
8165 // this.waitMsgTarget.unmask();
8167 // Roo.MessageBox.updateProgress(1);
8168 // Roo.MessageBox.hide();
8175 Roo.callback(o.success, o.scope, [this, action]);
8176 this.fireEvent('actioncomplete', this, action);
8180 // failure condition..
8181 // we have a scenario where updates need confirming.
8182 // eg. if a locking scenario exists..
8183 // we look for { errors : { needs_confirm : true }} in the response.
8185 (typeof(action.result) != 'undefined') &&
8186 (typeof(action.result.errors) != 'undefined') &&
8187 (typeof(action.result.errors.needs_confirm) != 'undefined')
8190 Roo.log("not supported yet");
8193 Roo.MessageBox.confirm(
8194 "Change requires confirmation",
8195 action.result.errorMsg,
8200 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8210 Roo.callback(o.failure, o.scope, [this, action]);
8211 // show an error message if no failed handler is set..
8212 if (!this.hasListener('actionfailed')) {
8213 Roo.log("need to add dialog support");
8215 Roo.MessageBox.alert("Error",
8216 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8217 action.result.errorMsg :
8218 "Saving Failed, please check your entries or try again"
8223 this.fireEvent('actionfailed', this, action);
8228 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8229 * @param {String} id The value to search for
8232 findField : function(id){
8233 var items = this.getItems();
8234 var field = items.get(id);
8236 items.each(function(f){
8237 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8244 return field || null;
8247 * Mark fields in this form invalid in bulk.
8248 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8249 * @return {BasicForm} this
8251 markInvalid : function(errors){
8252 if(errors instanceof Array){
8253 for(var i = 0, len = errors.length; i < len; i++){
8254 var fieldError = errors[i];
8255 var f = this.findField(fieldError.id);
8257 f.markInvalid(fieldError.msg);
8263 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8264 field.markInvalid(errors[id]);
8268 //Roo.each(this.childForms || [], function (f) {
8269 // f.markInvalid(errors);
8276 * Set values for fields in this form in bulk.
8277 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8278 * @return {BasicForm} this
8280 setValues : function(values){
8281 if(values instanceof Array){ // array of objects
8282 for(var i = 0, len = values.length; i < len; i++){
8284 var f = this.findField(v.id);
8286 f.setValue(v.value);
8287 if(this.trackResetOnLoad){
8288 f.originalValue = f.getValue();
8292 }else{ // object hash
8295 if(typeof values[id] != 'function' && (field = this.findField(id))){
8297 if (field.setFromData &&
8299 field.displayField &&
8300 // combos' with local stores can
8301 // be queried via setValue()
8302 // to set their value..
8303 (field.store && !field.store.isLocal)
8307 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8308 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8309 field.setFromData(sd);
8311 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8313 field.setFromData(values);
8316 field.setValue(values[id]);
8320 if(this.trackResetOnLoad){
8321 field.originalValue = field.getValue();
8327 //Roo.each(this.childForms || [], function (f) {
8328 // f.setValues(values);
8335 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8336 * they are returned as an array.
8337 * @param {Boolean} asString
8340 getValues : function(asString){
8341 //if (this.childForms) {
8342 // copy values from the child forms
8343 // Roo.each(this.childForms, function (f) {
8344 // this.setValues(f.getValues());
8350 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8351 if(asString === true){
8354 return Roo.urlDecode(fs);
8358 * Returns the fields in this form as an object with key/value pairs.
8359 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8362 getFieldValues : function(with_hidden)
8364 var items = this.getItems();
8366 items.each(function(f){
8372 var v = f.getValue();
8374 if (f.inputType =='radio') {
8375 if (typeof(ret[f.getName()]) == 'undefined') {
8376 ret[f.getName()] = ''; // empty..
8379 if (!f.el.dom.checked) {
8387 if(f.xtype == 'MoneyField'){
8388 ret[f.currencyName] = f.getCurrency();
8391 // not sure if this supported any more..
8392 if ((typeof(v) == 'object') && f.getRawValue) {
8393 v = f.getRawValue() ; // dates..
8395 // combo boxes where name != hiddenName...
8396 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8397 ret[f.name] = f.getRawValue();
8399 ret[f.getName()] = v;
8406 * Clears all invalid messages in this form.
8407 * @return {BasicForm} this
8409 clearInvalid : function(){
8410 var items = this.getItems();
8412 items.each(function(f){
8421 * @return {BasicForm} this
8424 var items = this.getItems();
8425 items.each(function(f){
8429 Roo.each(this.childForms || [], function (f) {
8437 getItems : function()
8439 var r=new Roo.util.MixedCollection(false, function(o){
8440 return o.id || (o.id = Roo.id());
8442 var iter = function(el) {
8449 Roo.each(el.items,function(e) {
8458 hideFields : function(items)
8460 Roo.each(items, function(i){
8462 var f = this.findField(i);
8473 showFields : function(items)
8475 Roo.each(items, function(i){
8477 var f = this.findField(i);
8490 Roo.apply(Roo.bootstrap.Form, {
8517 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8518 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8519 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8520 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8523 this.maskEl.top.enableDisplayMode("block");
8524 this.maskEl.left.enableDisplayMode("block");
8525 this.maskEl.bottom.enableDisplayMode("block");
8526 this.maskEl.right.enableDisplayMode("block");
8528 this.toolTip = new Roo.bootstrap.Tooltip({
8529 cls : 'roo-form-error-popover',
8531 'left' : ['r-l', [-2,0], 'right'],
8532 'right' : ['l-r', [2,0], 'left'],
8533 'bottom' : ['tl-bl', [0,2], 'top'],
8534 'top' : [ 'bl-tl', [0,-2], 'bottom']
8538 this.toolTip.render(Roo.get(document.body));
8540 this.toolTip.el.enableDisplayMode("block");
8542 Roo.get(document.body).on('click', function(){
8546 Roo.get(document.body).on('touchstart', function(){
8550 this.isApplied = true
8553 mask : function(form, target)
8557 this.target = target;
8559 if(!this.form.errorMask || !target.el){
8563 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8565 Roo.log(scrollable);
8567 var ot = this.target.el.calcOffsetsTo(scrollable);
8569 var scrollTo = ot[1] - this.form.maskOffset;
8571 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8573 scrollable.scrollTo('top', scrollTo);
8575 var box = this.target.el.getBox();
8577 var zIndex = Roo.bootstrap.Modal.zIndex++;
8580 this.maskEl.top.setStyle('position', 'absolute');
8581 this.maskEl.top.setStyle('z-index', zIndex);
8582 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8583 this.maskEl.top.setLeft(0);
8584 this.maskEl.top.setTop(0);
8585 this.maskEl.top.show();
8587 this.maskEl.left.setStyle('position', 'absolute');
8588 this.maskEl.left.setStyle('z-index', zIndex);
8589 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8590 this.maskEl.left.setLeft(0);
8591 this.maskEl.left.setTop(box.y - this.padding);
8592 this.maskEl.left.show();
8594 this.maskEl.bottom.setStyle('position', 'absolute');
8595 this.maskEl.bottom.setStyle('z-index', zIndex);
8596 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8597 this.maskEl.bottom.setLeft(0);
8598 this.maskEl.bottom.setTop(box.bottom + this.padding);
8599 this.maskEl.bottom.show();
8601 this.maskEl.right.setStyle('position', 'absolute');
8602 this.maskEl.right.setStyle('z-index', zIndex);
8603 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8604 this.maskEl.right.setLeft(box.right + this.padding);
8605 this.maskEl.right.setTop(box.y - this.padding);
8606 this.maskEl.right.show();
8608 this.toolTip.bindEl = this.target.el;
8610 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8612 var tip = this.target.blankText;
8614 if(this.target.getValue() !== '' ) {
8616 if (this.target.invalidText.length) {
8617 tip = this.target.invalidText;
8618 } else if (this.target.regexText.length){
8619 tip = this.target.regexText;
8623 this.toolTip.show(tip);
8625 this.intervalID = window.setInterval(function() {
8626 Roo.bootstrap.Form.popover.unmask();
8629 window.onwheel = function(){ return false;};
8631 (function(){ this.isMasked = true; }).defer(500, this);
8637 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8641 this.maskEl.top.setStyle('position', 'absolute');
8642 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8643 this.maskEl.top.hide();
8645 this.maskEl.left.setStyle('position', 'absolute');
8646 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8647 this.maskEl.left.hide();
8649 this.maskEl.bottom.setStyle('position', 'absolute');
8650 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8651 this.maskEl.bottom.hide();
8653 this.maskEl.right.setStyle('position', 'absolute');
8654 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8655 this.maskEl.right.hide();
8657 this.toolTip.hide();
8659 this.toolTip.el.hide();
8661 window.onwheel = function(){ return true;};
8663 if(this.intervalID){
8664 window.clearInterval(this.intervalID);
8665 this.intervalID = false;
8668 this.isMasked = false;
8678 * Ext JS Library 1.1.1
8679 * Copyright(c) 2006-2007, Ext JS, LLC.
8681 * Originally Released Under LGPL - original licence link has changed is not relivant.
8684 * <script type="text/javascript">
8687 * @class Roo.form.VTypes
8688 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8691 Roo.form.VTypes = function(){
8692 // closure these in so they are only created once.
8693 var alpha = /^[a-zA-Z_]+$/;
8694 var alphanum = /^[a-zA-Z0-9_]+$/;
8695 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8696 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8698 // All these messages and functions are configurable
8701 * The function used to validate email addresses
8702 * @param {String} value The email address
8704 'email' : function(v){
8705 return email.test(v);
8708 * The error text to display when the email validation function returns false
8711 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8713 * The keystroke filter mask to be applied on email input
8716 'emailMask' : /[a-z0-9_\.\-@]/i,
8719 * The function used to validate URLs
8720 * @param {String} value The URL
8722 'url' : function(v){
8726 * The error text to display when the url validation function returns false
8729 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8732 * The function used to validate alpha values
8733 * @param {String} value The value
8735 'alpha' : function(v){
8736 return alpha.test(v);
8739 * The error text to display when the alpha validation function returns false
8742 'alphaText' : 'This field should only contain letters and _',
8744 * The keystroke filter mask to be applied on alpha input
8747 'alphaMask' : /[a-z_]/i,
8750 * The function used to validate alphanumeric values
8751 * @param {String} value The value
8753 'alphanum' : function(v){
8754 return alphanum.test(v);
8757 * The error text to display when the alphanumeric validation function returns false
8760 'alphanumText' : 'This field should only contain letters, numbers and _',
8762 * The keystroke filter mask to be applied on alphanumeric input
8765 'alphanumMask' : /[a-z0-9_]/i
8775 * @class Roo.bootstrap.Input
8776 * @extends Roo.bootstrap.Component
8777 * Bootstrap Input class
8778 * @cfg {Boolean} disabled is it disabled
8779 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8780 * @cfg {String} name name of the input
8781 * @cfg {string} fieldLabel - the label associated
8782 * @cfg {string} placeholder - placeholder to put in text.
8783 * @cfg {string} before - input group add on before
8784 * @cfg {string} after - input group add on after
8785 * @cfg {string} size - (lg|sm) or leave empty..
8786 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8787 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8788 * @cfg {Number} md colspan out of 12 for computer-sized screens
8789 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8790 * @cfg {string} value default value of the input
8791 * @cfg {Number} labelWidth set the width of label
8792 * @cfg {Number} labellg set the width of label (1-12)
8793 * @cfg {Number} labelmd set the width of label (1-12)
8794 * @cfg {Number} labelsm set the width of label (1-12)
8795 * @cfg {Number} labelxs set the width of label (1-12)
8796 * @cfg {String} labelAlign (top|left)
8797 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8798 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8799 * @cfg {String} indicatorpos (left|right) default left
8800 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8801 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8803 * @cfg {String} align (left|center|right) Default left
8804 * @cfg {Boolean} forceFeedback (true|false) Default false
8807 * Create a new Input
8808 * @param {Object} config The config object
8811 Roo.bootstrap.Input = function(config){
8813 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8818 * Fires when this field receives input focus.
8819 * @param {Roo.form.Field} this
8824 * Fires when this field loses input focus.
8825 * @param {Roo.form.Field} this
8830 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8831 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8832 * @param {Roo.form.Field} this
8833 * @param {Roo.EventObject} e The event object
8838 * Fires just before the field blurs if the field value has changed.
8839 * @param {Roo.form.Field} this
8840 * @param {Mixed} newValue The new value
8841 * @param {Mixed} oldValue The original value
8846 * Fires after the field has been marked as invalid.
8847 * @param {Roo.form.Field} this
8848 * @param {String} msg The validation message
8853 * Fires after the field has been validated with no errors.
8854 * @param {Roo.form.Field} this
8859 * Fires after the key up
8860 * @param {Roo.form.Field} this
8861 * @param {Roo.EventObject} e The event Object
8867 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8869 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8870 automatic validation (defaults to "keyup").
8872 validationEvent : "keyup",
8874 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8876 validateOnBlur : true,
8878 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8880 validationDelay : 250,
8882 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8884 focusClass : "x-form-focus", // not needed???
8888 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8890 invalidClass : "has-warning",
8893 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8895 validClass : "has-success",
8898 * @cfg {Boolean} hasFeedback (true|false) default true
8903 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8905 invalidFeedbackClass : "glyphicon-warning-sign",
8908 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8910 validFeedbackClass : "glyphicon-ok",
8913 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8915 selectOnFocus : false,
8918 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8922 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8927 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8929 disableKeyFilter : false,
8932 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8936 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8940 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8942 blankText : "Please complete this mandatory field",
8945 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8949 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8951 maxLength : Number.MAX_VALUE,
8953 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8955 minLengthText : "The minimum length for this field is {0}",
8957 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8959 maxLengthText : "The maximum length for this field is {0}",
8963 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8964 * If available, this function will be called only after the basic validators all return true, and will be passed the
8965 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8969 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8970 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8971 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
8975 * @cfg {String} regexText -- Depricated - use Invalid Text
8980 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8986 autocomplete: false,
9005 formatedValue : false,
9006 forceFeedback : false,
9008 indicatorpos : 'left',
9018 parentLabelAlign : function()
9021 while (parent.parent()) {
9022 parent = parent.parent();
9023 if (typeof(parent.labelAlign) !='undefined') {
9024 return parent.labelAlign;
9031 getAutoCreate : function()
9033 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9039 if(this.inputType != 'hidden'){
9040 cfg.cls = 'form-group' //input-group
9046 type : this.inputType,
9048 cls : 'form-control',
9049 placeholder : this.placeholder || '',
9050 autocomplete : this.autocomplete || 'new-password'
9053 if(this.capture.length){
9054 input.capture = this.capture;
9057 if(this.accept.length){
9058 input.accept = this.accept + "/*";
9062 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9065 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9066 input.maxLength = this.maxLength;
9069 if (this.disabled) {
9070 input.disabled=true;
9073 if (this.readOnly) {
9074 input.readonly=true;
9078 input.name = this.name;
9082 input.cls += ' input-' + this.size;
9086 ['xs','sm','md','lg'].map(function(size){
9087 if (settings[size]) {
9088 cfg.cls += ' col-' + size + '-' + settings[size];
9092 var inputblock = input;
9096 cls: 'glyphicon form-control-feedback'
9099 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9102 cls : 'has-feedback',
9110 if (this.before || this.after) {
9113 cls : 'input-group',
9117 if (this.before && typeof(this.before) == 'string') {
9119 inputblock.cn.push({
9121 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9125 if (this.before && typeof(this.before) == 'object') {
9126 this.before = Roo.factory(this.before);
9128 inputblock.cn.push({
9130 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9131 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9135 inputblock.cn.push(input);
9137 if (this.after && typeof(this.after) == 'string') {
9138 inputblock.cn.push({
9140 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9144 if (this.after && typeof(this.after) == 'object') {
9145 this.after = Roo.factory(this.after);
9147 inputblock.cn.push({
9149 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9150 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9154 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9155 inputblock.cls += ' has-feedback';
9156 inputblock.cn.push(feedback);
9161 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9162 tooltip : 'This field is required'
9164 if (Roo.bootstrap.version == 4) {
9167 style : 'display-none'
9170 if (align ==='left' && this.fieldLabel.length) {
9172 cfg.cls += ' roo-form-group-label-left row';
9179 cls : 'control-label col-form-label',
9180 html : this.fieldLabel
9191 var labelCfg = cfg.cn[1];
9192 var contentCfg = cfg.cn[2];
9194 if(this.indicatorpos == 'right'){
9199 cls : 'control-label col-form-label',
9203 html : this.fieldLabel
9217 labelCfg = cfg.cn[0];
9218 contentCfg = cfg.cn[1];
9222 if(this.labelWidth > 12){
9223 labelCfg.style = "width: " + this.labelWidth + 'px';
9226 if(this.labelWidth < 13 && this.labelmd == 0){
9227 this.labelmd = this.labelWidth;
9230 if(this.labellg > 0){
9231 labelCfg.cls += ' col-lg-' + this.labellg;
9232 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9235 if(this.labelmd > 0){
9236 labelCfg.cls += ' col-md-' + this.labelmd;
9237 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9240 if(this.labelsm > 0){
9241 labelCfg.cls += ' col-sm-' + this.labelsm;
9242 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9245 if(this.labelxs > 0){
9246 labelCfg.cls += ' col-xs-' + this.labelxs;
9247 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9251 } else if ( this.fieldLabel.length) {
9256 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9257 tooltip : 'This field is required'
9261 //cls : 'input-group-addon',
9262 html : this.fieldLabel
9270 if(this.indicatorpos == 'right'){
9275 //cls : 'input-group-addon',
9276 html : this.fieldLabel
9281 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9282 tooltip : 'This field is required'
9302 if (this.parentType === 'Navbar' && this.parent().bar) {
9303 cfg.cls += ' navbar-form';
9306 if (this.parentType === 'NavGroup') {
9307 cfg.cls += ' navbar-form';
9315 * return the real input element.
9317 inputEl: function ()
9319 return this.el.select('input.form-control',true).first();
9322 tooltipEl : function()
9324 return this.inputEl();
9327 indicatorEl : function()
9329 if (Roo.bootstrap.version == 4) {
9330 return false; // not enabled in v4 yet.
9333 var indicator = this.el.select('i.roo-required-indicator',true).first();
9343 setDisabled : function(v)
9345 var i = this.inputEl().dom;
9347 i.removeAttribute('disabled');
9351 i.setAttribute('disabled','true');
9353 initEvents : function()
9356 this.inputEl().on("keydown" , this.fireKey, this);
9357 this.inputEl().on("focus", this.onFocus, this);
9358 this.inputEl().on("blur", this.onBlur, this);
9360 this.inputEl().relayEvent('keyup', this);
9362 this.indicator = this.indicatorEl();
9365 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9368 // reference to original value for reset
9369 this.originalValue = this.getValue();
9370 //Roo.form.TextField.superclass.initEvents.call(this);
9371 if(this.validationEvent == 'keyup'){
9372 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9373 this.inputEl().on('keyup', this.filterValidation, this);
9375 else if(this.validationEvent !== false){
9376 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9379 if(this.selectOnFocus){
9380 this.on("focus", this.preFocus, this);
9383 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9384 this.inputEl().on("keypress", this.filterKeys, this);
9386 this.inputEl().relayEvent('keypress', this);
9389 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9390 this.el.on("click", this.autoSize, this);
9393 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9394 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9397 if (typeof(this.before) == 'object') {
9398 this.before.render(this.el.select('.roo-input-before',true).first());
9400 if (typeof(this.after) == 'object') {
9401 this.after.render(this.el.select('.roo-input-after',true).first());
9404 this.inputEl().on('change', this.onChange, this);
9407 filterValidation : function(e){
9408 if(!e.isNavKeyPress()){
9409 this.validationTask.delay(this.validationDelay);
9413 * Validates the field value
9414 * @return {Boolean} True if the value is valid, else false
9416 validate : function(){
9417 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9418 if(this.disabled || this.validateValue(this.getRawValue())){
9429 * Validates a value according to the field's validation rules and marks the field as invalid
9430 * if the validation fails
9431 * @param {Mixed} value The value to validate
9432 * @return {Boolean} True if the value is valid, else false
9434 validateValue : function(value)
9436 if(this.getVisibilityEl().hasClass('hidden')){
9440 if(value.length < 1) { // if it's blank
9441 if(this.allowBlank){
9447 if(value.length < this.minLength){
9450 if(value.length > this.maxLength){
9454 var vt = Roo.form.VTypes;
9455 if(!vt[this.vtype](value, this)){
9459 if(typeof this.validator == "function"){
9460 var msg = this.validator(value);
9464 if (typeof(msg) == 'string') {
9465 this.invalidText = msg;
9469 if(this.regex && !this.regex.test(value)){
9477 fireKey : function(e){
9478 //Roo.log('field ' + e.getKey());
9479 if(e.isNavKeyPress()){
9480 this.fireEvent("specialkey", this, e);
9483 focus : function (selectText){
9485 this.inputEl().focus();
9486 if(selectText === true){
9487 this.inputEl().dom.select();
9493 onFocus : function(){
9494 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9495 // this.el.addClass(this.focusClass);
9498 this.hasFocus = true;
9499 this.startValue = this.getValue();
9500 this.fireEvent("focus", this);
9504 beforeBlur : Roo.emptyFn,
9508 onBlur : function(){
9510 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9511 //this.el.removeClass(this.focusClass);
9513 this.hasFocus = false;
9514 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9517 var v = this.getValue();
9518 if(String(v) !== String(this.startValue)){
9519 this.fireEvent('change', this, v, this.startValue);
9521 this.fireEvent("blur", this);
9524 onChange : function(e)
9526 var v = this.getValue();
9527 if(String(v) !== String(this.startValue)){
9528 this.fireEvent('change', this, v, this.startValue);
9534 * Resets the current field value to the originally loaded value and clears any validation messages
9537 this.setValue(this.originalValue);
9541 * Returns the name of the field
9542 * @return {Mixed} name The name field
9544 getName: function(){
9548 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9549 * @return {Mixed} value The field value
9551 getValue : function(){
9553 var v = this.inputEl().getValue();
9558 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9559 * @return {Mixed} value The field value
9561 getRawValue : function(){
9562 var v = this.inputEl().getValue();
9568 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9569 * @param {Mixed} value The value to set
9571 setRawValue : function(v){
9572 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9575 selectText : function(start, end){
9576 var v = this.getRawValue();
9578 start = start === undefined ? 0 : start;
9579 end = end === undefined ? v.length : end;
9580 var d = this.inputEl().dom;
9581 if(d.setSelectionRange){
9582 d.setSelectionRange(start, end);
9583 }else if(d.createTextRange){
9584 var range = d.createTextRange();
9585 range.moveStart("character", start);
9586 range.moveEnd("character", v.length-end);
9593 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9594 * @param {Mixed} value The value to set
9596 setValue : function(v){
9599 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9605 processValue : function(value){
9606 if(this.stripCharsRe){
9607 var newValue = value.replace(this.stripCharsRe, '');
9608 if(newValue !== value){
9609 this.setRawValue(newValue);
9616 preFocus : function(){
9618 if(this.selectOnFocus){
9619 this.inputEl().dom.select();
9622 filterKeys : function(e){
9624 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9627 var c = e.getCharCode(), cc = String.fromCharCode(c);
9628 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9631 if(!this.maskRe.test(cc)){
9636 * Clear any invalid styles/messages for this field
9638 clearInvalid : function(){
9640 if(!this.el || this.preventMark){ // not rendered
9645 this.el.removeClass(this.invalidClass);
9647 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9649 var feedback = this.el.select('.form-control-feedback', true).first();
9652 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9658 this.indicator.removeClass('visible');
9659 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9662 this.fireEvent('valid', this);
9666 * Mark this field as valid
9668 markValid : function()
9670 if(!this.el || this.preventMark){ // not rendered...
9674 this.el.removeClass([this.invalidClass, this.validClass]);
9676 var feedback = this.el.select('.form-control-feedback', true).first();
9679 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9683 this.indicator.removeClass('visible');
9684 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9691 if(this.allowBlank && !this.getRawValue().length){
9695 this.el.addClass(this.validClass);
9697 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9699 var feedback = this.el.select('.form-control-feedback', true).first();
9702 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9703 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9708 this.fireEvent('valid', this);
9712 * Mark this field as invalid
9713 * @param {String} msg The validation message
9715 markInvalid : function(msg)
9717 if(!this.el || this.preventMark){ // not rendered
9721 this.el.removeClass([this.invalidClass, this.validClass]);
9723 var feedback = this.el.select('.form-control-feedback', true).first();
9726 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9733 if(this.allowBlank && !this.getRawValue().length){
9738 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9739 this.indicator.addClass('visible');
9742 this.el.addClass(this.invalidClass);
9744 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9746 var feedback = this.el.select('.form-control-feedback', true).first();
9749 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9751 if(this.getValue().length || this.forceFeedback){
9752 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9759 this.fireEvent('invalid', this, msg);
9762 SafariOnKeyDown : function(event)
9764 // this is a workaround for a password hang bug on chrome/ webkit.
9765 if (this.inputEl().dom.type != 'password') {
9769 var isSelectAll = false;
9771 if(this.inputEl().dom.selectionEnd > 0){
9772 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9774 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9775 event.preventDefault();
9780 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9782 event.preventDefault();
9783 // this is very hacky as keydown always get's upper case.
9785 var cc = String.fromCharCode(event.getCharCode());
9786 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9790 adjustWidth : function(tag, w){
9791 tag = tag.toLowerCase();
9792 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9793 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9797 if(tag == 'textarea'){
9800 }else if(Roo.isOpera){
9804 if(tag == 'textarea'){
9812 setFieldLabel : function(v)
9818 if(this.indicatorEl()){
9819 var ar = this.el.select('label > span',true);
9821 if (ar.elements.length) {
9822 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9823 this.fieldLabel = v;
9827 var br = this.el.select('label',true);
9829 if(br.elements.length) {
9830 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9831 this.fieldLabel = v;
9835 Roo.log('Cannot Found any of label > span || label in input');
9839 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9840 this.fieldLabel = v;
9855 * @class Roo.bootstrap.TextArea
9856 * @extends Roo.bootstrap.Input
9857 * Bootstrap TextArea class
9858 * @cfg {Number} cols Specifies the visible width of a text area
9859 * @cfg {Number} rows Specifies the visible number of lines in a text area
9860 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9861 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9862 * @cfg {string} html text
9865 * Create a new TextArea
9866 * @param {Object} config The config object
9869 Roo.bootstrap.TextArea = function(config){
9870 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9874 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9884 getAutoCreate : function(){
9886 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9892 if(this.inputType != 'hidden'){
9893 cfg.cls = 'form-group' //input-group
9901 value : this.value || '',
9902 html: this.html || '',
9903 cls : 'form-control',
9904 placeholder : this.placeholder || ''
9908 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9909 input.maxLength = this.maxLength;
9913 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9917 input.cols = this.cols;
9920 if (this.readOnly) {
9921 input.readonly = true;
9925 input.name = this.name;
9929 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9933 ['xs','sm','md','lg'].map(function(size){
9934 if (settings[size]) {
9935 cfg.cls += ' col-' + size + '-' + settings[size];
9939 var inputblock = input;
9941 if(this.hasFeedback && !this.allowBlank){
9945 cls: 'glyphicon form-control-feedback'
9949 cls : 'has-feedback',
9958 if (this.before || this.after) {
9961 cls : 'input-group',
9965 inputblock.cn.push({
9967 cls : 'input-group-addon',
9972 inputblock.cn.push(input);
9974 if(this.hasFeedback && !this.allowBlank){
9975 inputblock.cls += ' has-feedback';
9976 inputblock.cn.push(feedback);
9980 inputblock.cn.push({
9982 cls : 'input-group-addon',
9989 if (align ==='left' && this.fieldLabel.length) {
9994 cls : 'control-label',
9995 html : this.fieldLabel
10006 if(this.labelWidth > 12){
10007 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10010 if(this.labelWidth < 13 && this.labelmd == 0){
10011 this.labelmd = this.labelWidth;
10014 if(this.labellg > 0){
10015 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10016 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10019 if(this.labelmd > 0){
10020 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10021 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10024 if(this.labelsm > 0){
10025 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10026 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10029 if(this.labelxs > 0){
10030 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10031 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10034 } else if ( this.fieldLabel.length) {
10039 //cls : 'input-group-addon',
10040 html : this.fieldLabel
10058 if (this.disabled) {
10059 input.disabled=true;
10066 * return the real textarea element.
10068 inputEl: function ()
10070 return this.el.select('textarea.form-control',true).first();
10074 * Clear any invalid styles/messages for this field
10076 clearInvalid : function()
10079 if(!this.el || this.preventMark){ // not rendered
10083 var label = this.el.select('label', true).first();
10084 var icon = this.el.select('i.fa-star', true).first();
10090 this.el.removeClass(this.invalidClass);
10092 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10094 var feedback = this.el.select('.form-control-feedback', true).first();
10097 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10102 this.fireEvent('valid', this);
10106 * Mark this field as valid
10108 markValid : function()
10110 if(!this.el || this.preventMark){ // not rendered
10114 this.el.removeClass([this.invalidClass, this.validClass]);
10116 var feedback = this.el.select('.form-control-feedback', true).first();
10119 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10122 if(this.disabled || this.allowBlank){
10126 var label = this.el.select('label', true).first();
10127 var icon = this.el.select('i.fa-star', true).first();
10133 this.el.addClass(this.validClass);
10135 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10137 var feedback = this.el.select('.form-control-feedback', true).first();
10140 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10141 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10146 this.fireEvent('valid', this);
10150 * Mark this field as invalid
10151 * @param {String} msg The validation message
10153 markInvalid : function(msg)
10155 if(!this.el || this.preventMark){ // not rendered
10159 this.el.removeClass([this.invalidClass, this.validClass]);
10161 var feedback = this.el.select('.form-control-feedback', true).first();
10164 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10167 if(this.disabled || this.allowBlank){
10171 var label = this.el.select('label', true).first();
10172 var icon = this.el.select('i.fa-star', true).first();
10174 if(!this.getValue().length && label && !icon){
10175 this.el.createChild({
10177 cls : 'text-danger fa fa-lg fa-star',
10178 tooltip : 'This field is required',
10179 style : 'margin-right:5px;'
10183 this.el.addClass(this.invalidClass);
10185 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10187 var feedback = this.el.select('.form-control-feedback', true).first();
10190 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10192 if(this.getValue().length || this.forceFeedback){
10193 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10200 this.fireEvent('invalid', this, msg);
10208 * trigger field - base class for combo..
10213 * @class Roo.bootstrap.TriggerField
10214 * @extends Roo.bootstrap.Input
10215 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10216 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10217 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10218 * for which you can provide a custom implementation. For example:
10220 var trigger = new Roo.bootstrap.TriggerField();
10221 trigger.onTriggerClick = myTriggerFn;
10222 trigger.applyTo('my-field');
10225 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10226 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10227 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10228 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10229 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10232 * Create a new TriggerField.
10233 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10234 * to the base TextField)
10236 Roo.bootstrap.TriggerField = function(config){
10237 this.mimicing = false;
10238 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10241 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10243 * @cfg {String} triggerClass A CSS class to apply to the trigger
10246 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10251 * @cfg {Boolean} removable (true|false) special filter default false
10255 /** @cfg {Boolean} grow @hide */
10256 /** @cfg {Number} growMin @hide */
10257 /** @cfg {Number} growMax @hide */
10263 autoSize: Roo.emptyFn,
10267 deferHeight : true,
10270 actionMode : 'wrap',
10275 getAutoCreate : function(){
10277 var align = this.labelAlign || this.parentLabelAlign();
10282 cls: 'form-group' //input-group
10289 type : this.inputType,
10290 cls : 'form-control',
10291 autocomplete: 'new-password',
10292 placeholder : this.placeholder || ''
10296 input.name = this.name;
10299 input.cls += ' input-' + this.size;
10302 if (this.disabled) {
10303 input.disabled=true;
10306 var inputblock = input;
10308 if(this.hasFeedback && !this.allowBlank){
10312 cls: 'glyphicon form-control-feedback'
10315 if(this.removable && !this.editable && !this.tickable){
10317 cls : 'has-feedback',
10323 cls : 'roo-combo-removable-btn close'
10330 cls : 'has-feedback',
10339 if(this.removable && !this.editable && !this.tickable){
10341 cls : 'roo-removable',
10347 cls : 'roo-combo-removable-btn close'
10354 if (this.before || this.after) {
10357 cls : 'input-group',
10361 inputblock.cn.push({
10363 cls : 'input-group-addon input-group-prepend input-group-text',
10368 inputblock.cn.push(input);
10370 if(this.hasFeedback && !this.allowBlank){
10371 inputblock.cls += ' has-feedback';
10372 inputblock.cn.push(feedback);
10376 inputblock.cn.push({
10378 cls : 'input-group-addon input-group-append input-group-text',
10391 cls: 'form-hidden-field'
10405 cls: 'form-hidden-field'
10409 cls: 'roo-select2-choices',
10413 cls: 'roo-select2-search-field',
10426 cls: 'roo-select2-container input-group',
10431 // cls: 'typeahead typeahead-long dropdown-menu',
10432 // style: 'display:none'
10437 if(!this.multiple && this.showToggleBtn){
10443 if (this.caret != false) {
10446 cls: 'fa fa-' + this.caret
10453 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10458 cls: 'combobox-clear',
10472 combobox.cls += ' roo-select2-container-multi';
10476 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10477 tooltip : 'This field is required'
10479 if (Roo.bootstrap.version == 4) {
10482 style : 'display:none'
10487 if (align ==='left' && this.fieldLabel.length) {
10489 cfg.cls += ' roo-form-group-label-left row';
10496 cls : 'control-label',
10497 html : this.fieldLabel
10509 var labelCfg = cfg.cn[1];
10510 var contentCfg = cfg.cn[2];
10512 if(this.indicatorpos == 'right'){
10517 cls : 'control-label',
10521 html : this.fieldLabel
10535 labelCfg = cfg.cn[0];
10536 contentCfg = cfg.cn[1];
10539 if(this.labelWidth > 12){
10540 labelCfg.style = "width: " + this.labelWidth + 'px';
10543 if(this.labelWidth < 13 && this.labelmd == 0){
10544 this.labelmd = this.labelWidth;
10547 if(this.labellg > 0){
10548 labelCfg.cls += ' col-lg-' + this.labellg;
10549 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10552 if(this.labelmd > 0){
10553 labelCfg.cls += ' col-md-' + this.labelmd;
10554 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10557 if(this.labelsm > 0){
10558 labelCfg.cls += ' col-sm-' + this.labelsm;
10559 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10562 if(this.labelxs > 0){
10563 labelCfg.cls += ' col-xs-' + this.labelxs;
10564 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10567 } else if ( this.fieldLabel.length) {
10568 // Roo.log(" label");
10573 //cls : 'input-group-addon',
10574 html : this.fieldLabel
10582 if(this.indicatorpos == 'right'){
10590 html : this.fieldLabel
10604 // Roo.log(" no label && no align");
10611 ['xs','sm','md','lg'].map(function(size){
10612 if (settings[size]) {
10613 cfg.cls += ' col-' + size + '-' + settings[size];
10624 onResize : function(w, h){
10625 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10626 // if(typeof w == 'number'){
10627 // var x = w - this.trigger.getWidth();
10628 // this.inputEl().setWidth(this.adjustWidth('input', x));
10629 // this.trigger.setStyle('left', x+'px');
10634 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10637 getResizeEl : function(){
10638 return this.inputEl();
10642 getPositionEl : function(){
10643 return this.inputEl();
10647 alignErrorIcon : function(){
10648 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10652 initEvents : function(){
10656 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10657 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10658 if(!this.multiple && this.showToggleBtn){
10659 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10660 if(this.hideTrigger){
10661 this.trigger.setDisplayed(false);
10663 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10667 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10670 if(this.removable && !this.editable && !this.tickable){
10671 var close = this.closeTriggerEl();
10674 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10675 close.on('click', this.removeBtnClick, this, close);
10679 //this.trigger.addClassOnOver('x-form-trigger-over');
10680 //this.trigger.addClassOnClick('x-form-trigger-click');
10683 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10687 closeTriggerEl : function()
10689 var close = this.el.select('.roo-combo-removable-btn', true).first();
10690 return close ? close : false;
10693 removeBtnClick : function(e, h, el)
10695 e.preventDefault();
10697 if(this.fireEvent("remove", this) !== false){
10699 this.fireEvent("afterremove", this)
10703 createList : function()
10705 this.list = Roo.get(document.body).createChild({
10707 cls: 'typeahead typeahead-long dropdown-menu',
10708 style: 'display:none'
10711 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10716 initTrigger : function(){
10721 onDestroy : function(){
10723 this.trigger.removeAllListeners();
10724 // this.trigger.remove();
10727 // this.wrap.remove();
10729 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10733 onFocus : function(){
10734 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10736 if(!this.mimicing){
10737 this.wrap.addClass('x-trigger-wrap-focus');
10738 this.mimicing = true;
10739 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10740 if(this.monitorTab){
10741 this.el.on("keydown", this.checkTab, this);
10748 checkTab : function(e){
10749 if(e.getKey() == e.TAB){
10750 this.triggerBlur();
10755 onBlur : function(){
10760 mimicBlur : function(e, t){
10762 if(!this.wrap.contains(t) && this.validateBlur()){
10763 this.triggerBlur();
10769 triggerBlur : function(){
10770 this.mimicing = false;
10771 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10772 if(this.monitorTab){
10773 this.el.un("keydown", this.checkTab, this);
10775 //this.wrap.removeClass('x-trigger-wrap-focus');
10776 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10780 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10781 validateBlur : function(e, t){
10786 onDisable : function(){
10787 this.inputEl().dom.disabled = true;
10788 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10790 // this.wrap.addClass('x-item-disabled');
10795 onEnable : function(){
10796 this.inputEl().dom.disabled = false;
10797 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10799 // this.el.removeClass('x-item-disabled');
10804 onShow : function(){
10805 var ae = this.getActionEl();
10808 ae.dom.style.display = '';
10809 ae.dom.style.visibility = 'visible';
10815 onHide : function(){
10816 var ae = this.getActionEl();
10817 ae.dom.style.display = 'none';
10821 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10822 * by an implementing function.
10824 * @param {EventObject} e
10826 onTriggerClick : Roo.emptyFn
10830 * Ext JS Library 1.1.1
10831 * Copyright(c) 2006-2007, Ext JS, LLC.
10833 * Originally Released Under LGPL - original licence link has changed is not relivant.
10836 * <script type="text/javascript">
10841 * @class Roo.data.SortTypes
10843 * Defines the default sorting (casting?) comparison functions used when sorting data.
10845 Roo.data.SortTypes = {
10847 * Default sort that does nothing
10848 * @param {Mixed} s The value being converted
10849 * @return {Mixed} The comparison value
10851 none : function(s){
10856 * The regular expression used to strip tags
10860 stripTagsRE : /<\/?[^>]+>/gi,
10863 * Strips all HTML tags to sort on text only
10864 * @param {Mixed} s The value being converted
10865 * @return {String} The comparison value
10867 asText : function(s){
10868 return String(s).replace(this.stripTagsRE, "");
10872 * Strips all HTML tags to sort on text only - Case insensitive
10873 * @param {Mixed} s The value being converted
10874 * @return {String} The comparison value
10876 asUCText : function(s){
10877 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10881 * Case insensitive string
10882 * @param {Mixed} s The value being converted
10883 * @return {String} The comparison value
10885 asUCString : function(s) {
10886 return String(s).toUpperCase();
10891 * @param {Mixed} s The value being converted
10892 * @return {Number} The comparison value
10894 asDate : function(s) {
10898 if(s instanceof Date){
10899 return s.getTime();
10901 return Date.parse(String(s));
10906 * @param {Mixed} s The value being converted
10907 * @return {Float} The comparison value
10909 asFloat : function(s) {
10910 var val = parseFloat(String(s).replace(/,/g, ""));
10919 * @param {Mixed} s The value being converted
10920 * @return {Number} The comparison value
10922 asInt : function(s) {
10923 var val = parseInt(String(s).replace(/,/g, ""));
10931 * Ext JS Library 1.1.1
10932 * Copyright(c) 2006-2007, Ext JS, LLC.
10934 * Originally Released Under LGPL - original licence link has changed is not relivant.
10937 * <script type="text/javascript">
10941 * @class Roo.data.Record
10942 * Instances of this class encapsulate both record <em>definition</em> information, and record
10943 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10944 * to access Records cached in an {@link Roo.data.Store} object.<br>
10946 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10947 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10950 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10952 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10953 * {@link #create}. The parameters are the same.
10954 * @param {Array} data An associative Array of data values keyed by the field name.
10955 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10956 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10957 * not specified an integer id is generated.
10959 Roo.data.Record = function(data, id){
10960 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10965 * Generate a constructor for a specific record layout.
10966 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10967 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10968 * Each field definition object may contain the following properties: <ul>
10969 * <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,
10970 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10971 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10972 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10973 * is being used, then this is a string containing the javascript expression to reference the data relative to
10974 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10975 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10976 * this may be omitted.</p></li>
10977 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10978 * <ul><li>auto (Default, implies no conversion)</li>
10983 * <li>date</li></ul></p></li>
10984 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10985 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10986 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10987 * by the Reader into an object that will be stored in the Record. It is passed the
10988 * following parameters:<ul>
10989 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10991 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10993 * <br>usage:<br><pre><code>
10994 var TopicRecord = Roo.data.Record.create(
10995 {name: 'title', mapping: 'topic_title'},
10996 {name: 'author', mapping: 'username'},
10997 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10998 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10999 {name: 'lastPoster', mapping: 'user2'},
11000 {name: 'excerpt', mapping: 'post_text'}
11003 var myNewRecord = new TopicRecord({
11004 title: 'Do my job please',
11007 lastPost: new Date(),
11008 lastPoster: 'Animal',
11009 excerpt: 'No way dude!'
11011 myStore.add(myNewRecord);
11016 Roo.data.Record.create = function(o){
11017 var f = function(){
11018 f.superclass.constructor.apply(this, arguments);
11020 Roo.extend(f, Roo.data.Record);
11021 var p = f.prototype;
11022 p.fields = new Roo.util.MixedCollection(false, function(field){
11025 for(var i = 0, len = o.length; i < len; i++){
11026 p.fields.add(new Roo.data.Field(o[i]));
11028 f.getField = function(name){
11029 return p.fields.get(name);
11034 Roo.data.Record.AUTO_ID = 1000;
11035 Roo.data.Record.EDIT = 'edit';
11036 Roo.data.Record.REJECT = 'reject';
11037 Roo.data.Record.COMMIT = 'commit';
11039 Roo.data.Record.prototype = {
11041 * Readonly flag - true if this record has been modified.
11050 join : function(store){
11051 this.store = store;
11055 * Set the named field to the specified value.
11056 * @param {String} name The name of the field to set.
11057 * @param {Object} value The value to set the field to.
11059 set : function(name, value){
11060 if(this.data[name] == value){
11064 if(!this.modified){
11065 this.modified = {};
11067 if(typeof this.modified[name] == 'undefined'){
11068 this.modified[name] = this.data[name];
11070 this.data[name] = value;
11071 if(!this.editing && this.store){
11072 this.store.afterEdit(this);
11077 * Get the value of the named field.
11078 * @param {String} name The name of the field to get the value of.
11079 * @return {Object} The value of the field.
11081 get : function(name){
11082 return this.data[name];
11086 beginEdit : function(){
11087 this.editing = true;
11088 this.modified = {};
11092 cancelEdit : function(){
11093 this.editing = false;
11094 delete this.modified;
11098 endEdit : function(){
11099 this.editing = false;
11100 if(this.dirty && this.store){
11101 this.store.afterEdit(this);
11106 * Usually called by the {@link Roo.data.Store} which owns the Record.
11107 * Rejects all changes made to the Record since either creation, or the last commit operation.
11108 * Modified fields are reverted to their original values.
11110 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11111 * of reject operations.
11113 reject : function(){
11114 var m = this.modified;
11116 if(typeof m[n] != "function"){
11117 this.data[n] = m[n];
11120 this.dirty = false;
11121 delete this.modified;
11122 this.editing = false;
11124 this.store.afterReject(this);
11129 * Usually called by the {@link Roo.data.Store} which owns the Record.
11130 * Commits all changes made to the Record since either creation, or the last commit operation.
11132 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11133 * of commit operations.
11135 commit : function(){
11136 this.dirty = false;
11137 delete this.modified;
11138 this.editing = false;
11140 this.store.afterCommit(this);
11145 hasError : function(){
11146 return this.error != null;
11150 clearError : function(){
11155 * Creates a copy of this record.
11156 * @param {String} id (optional) A new record id if you don't want to use this record's id
11159 copy : function(newId) {
11160 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11164 * Ext JS Library 1.1.1
11165 * Copyright(c) 2006-2007, Ext JS, LLC.
11167 * Originally Released Under LGPL - original licence link has changed is not relivant.
11170 * <script type="text/javascript">
11176 * @class Roo.data.Store
11177 * @extends Roo.util.Observable
11178 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11179 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11181 * 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
11182 * has no knowledge of the format of the data returned by the Proxy.<br>
11184 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11185 * instances from the data object. These records are cached and made available through accessor functions.
11187 * Creates a new Store.
11188 * @param {Object} config A config object containing the objects needed for the Store to access data,
11189 * and read the data into Records.
11191 Roo.data.Store = function(config){
11192 this.data = new Roo.util.MixedCollection(false);
11193 this.data.getKey = function(o){
11196 this.baseParams = {};
11198 this.paramNames = {
11203 "multisort" : "_multisort"
11206 if(config && config.data){
11207 this.inlineData = config.data;
11208 delete config.data;
11211 Roo.apply(this, config);
11213 if(this.reader){ // reader passed
11214 this.reader = Roo.factory(this.reader, Roo.data);
11215 this.reader.xmodule = this.xmodule || false;
11216 if(!this.recordType){
11217 this.recordType = this.reader.recordType;
11219 if(this.reader.onMetaChange){
11220 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11224 if(this.recordType){
11225 this.fields = this.recordType.prototype.fields;
11227 this.modified = [];
11231 * @event datachanged
11232 * Fires when the data cache has changed, and a widget which is using this Store
11233 * as a Record cache should refresh its view.
11234 * @param {Store} this
11236 datachanged : true,
11238 * @event metachange
11239 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11240 * @param {Store} this
11241 * @param {Object} meta The JSON metadata
11246 * Fires when Records have been added to the Store
11247 * @param {Store} this
11248 * @param {Roo.data.Record[]} records The array of Records added
11249 * @param {Number} index The index at which the record(s) were added
11254 * Fires when a Record has been removed from the Store
11255 * @param {Store} this
11256 * @param {Roo.data.Record} record The Record that was removed
11257 * @param {Number} index The index at which the record was removed
11262 * Fires when a Record has been updated
11263 * @param {Store} this
11264 * @param {Roo.data.Record} record The Record that was updated
11265 * @param {String} operation The update operation being performed. Value may be one of:
11267 Roo.data.Record.EDIT
11268 Roo.data.Record.REJECT
11269 Roo.data.Record.COMMIT
11275 * Fires when the data cache has been cleared.
11276 * @param {Store} this
11280 * @event beforeload
11281 * Fires before a request is made for a new data object. If the beforeload handler returns false
11282 * the load action will be canceled.
11283 * @param {Store} this
11284 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11288 * @event beforeloadadd
11289 * Fires after a new set of Records has been loaded.
11290 * @param {Store} this
11291 * @param {Roo.data.Record[]} records The Records that were loaded
11292 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11294 beforeloadadd : true,
11297 * Fires after a new set of Records has been loaded, before they are added to the store.
11298 * @param {Store} this
11299 * @param {Roo.data.Record[]} records The Records that were loaded
11300 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11301 * @params {Object} return from reader
11305 * @event loadexception
11306 * Fires if an exception occurs in the Proxy during loading.
11307 * Called with the signature of the Proxy's "loadexception" event.
11308 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11311 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11312 * @param {Object} load options
11313 * @param {Object} jsonData from your request (normally this contains the Exception)
11315 loadexception : true
11319 this.proxy = Roo.factory(this.proxy, Roo.data);
11320 this.proxy.xmodule = this.xmodule || false;
11321 this.relayEvents(this.proxy, ["loadexception"]);
11323 this.sortToggle = {};
11324 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11326 Roo.data.Store.superclass.constructor.call(this);
11328 if(this.inlineData){
11329 this.loadData(this.inlineData);
11330 delete this.inlineData;
11334 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11336 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11337 * without a remote query - used by combo/forms at present.
11341 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11344 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11347 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11348 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11351 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11352 * on any HTTP request
11355 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11358 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11362 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11363 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11365 remoteSort : false,
11368 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11369 * loaded or when a record is removed. (defaults to false).
11371 pruneModifiedRecords : false,
11374 lastOptions : null,
11377 * Add Records to the Store and fires the add event.
11378 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11380 add : function(records){
11381 records = [].concat(records);
11382 for(var i = 0, len = records.length; i < len; i++){
11383 records[i].join(this);
11385 var index = this.data.length;
11386 this.data.addAll(records);
11387 this.fireEvent("add", this, records, index);
11391 * Remove a Record from the Store and fires the remove event.
11392 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11394 remove : function(record){
11395 var index = this.data.indexOf(record);
11396 this.data.removeAt(index);
11398 if(this.pruneModifiedRecords){
11399 this.modified.remove(record);
11401 this.fireEvent("remove", this, record, index);
11405 * Remove all Records from the Store and fires the clear event.
11407 removeAll : function(){
11409 if(this.pruneModifiedRecords){
11410 this.modified = [];
11412 this.fireEvent("clear", this);
11416 * Inserts Records to the Store at the given index and fires the add event.
11417 * @param {Number} index The start index at which to insert the passed Records.
11418 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11420 insert : function(index, records){
11421 records = [].concat(records);
11422 for(var i = 0, len = records.length; i < len; i++){
11423 this.data.insert(index, records[i]);
11424 records[i].join(this);
11426 this.fireEvent("add", this, records, index);
11430 * Get the index within the cache of the passed Record.
11431 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11432 * @return {Number} The index of the passed Record. Returns -1 if not found.
11434 indexOf : function(record){
11435 return this.data.indexOf(record);
11439 * Get the index within the cache of the Record with the passed id.
11440 * @param {String} id The id of the Record to find.
11441 * @return {Number} The index of the Record. Returns -1 if not found.
11443 indexOfId : function(id){
11444 return this.data.indexOfKey(id);
11448 * Get the Record with the specified id.
11449 * @param {String} id The id of the Record to find.
11450 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11452 getById : function(id){
11453 return this.data.key(id);
11457 * Get the Record at the specified index.
11458 * @param {Number} index The index of the Record to find.
11459 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11461 getAt : function(index){
11462 return this.data.itemAt(index);
11466 * Returns a range of Records between specified indices.
11467 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11468 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11469 * @return {Roo.data.Record[]} An array of Records
11471 getRange : function(start, end){
11472 return this.data.getRange(start, end);
11476 storeOptions : function(o){
11477 o = Roo.apply({}, o);
11480 this.lastOptions = o;
11484 * Loads the Record cache from the configured Proxy using the configured Reader.
11486 * If using remote paging, then the first load call must specify the <em>start</em>
11487 * and <em>limit</em> properties in the options.params property to establish the initial
11488 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11490 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11491 * and this call will return before the new data has been loaded. Perform any post-processing
11492 * in a callback function, or in a "load" event handler.</strong>
11494 * @param {Object} options An object containing properties which control loading options:<ul>
11495 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11496 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11497 * passed the following arguments:<ul>
11498 * <li>r : Roo.data.Record[]</li>
11499 * <li>options: Options object from the load call</li>
11500 * <li>success: Boolean success indicator</li></ul></li>
11501 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11502 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11505 load : function(options){
11506 options = options || {};
11507 if(this.fireEvent("beforeload", this, options) !== false){
11508 this.storeOptions(options);
11509 var p = Roo.apply(options.params || {}, this.baseParams);
11510 // if meta was not loaded from remote source.. try requesting it.
11511 if (!this.reader.metaFromRemote) {
11512 p._requestMeta = 1;
11514 if(this.sortInfo && this.remoteSort){
11515 var pn = this.paramNames;
11516 p[pn["sort"]] = this.sortInfo.field;
11517 p[pn["dir"]] = this.sortInfo.direction;
11519 if (this.multiSort) {
11520 var pn = this.paramNames;
11521 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11524 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11529 * Reloads the Record cache from the configured Proxy using the configured Reader and
11530 * the options from the last load operation performed.
11531 * @param {Object} options (optional) An object containing properties which may override the options
11532 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11533 * the most recently used options are reused).
11535 reload : function(options){
11536 this.load(Roo.applyIf(options||{}, this.lastOptions));
11540 // Called as a callback by the Reader during a load operation.
11541 loadRecords : function(o, options, success){
11542 if(!o || success === false){
11543 if(success !== false){
11544 this.fireEvent("load", this, [], options, o);
11546 if(options.callback){
11547 options.callback.call(options.scope || this, [], options, false);
11551 // if data returned failure - throw an exception.
11552 if (o.success === false) {
11553 // show a message if no listener is registered.
11554 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11555 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11557 // loadmask wil be hooked into this..
11558 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11561 var r = o.records, t = o.totalRecords || r.length;
11563 this.fireEvent("beforeloadadd", this, r, options, o);
11565 if(!options || options.add !== true){
11566 if(this.pruneModifiedRecords){
11567 this.modified = [];
11569 for(var i = 0, len = r.length; i < len; i++){
11573 this.data = this.snapshot;
11574 delete this.snapshot;
11577 this.data.addAll(r);
11578 this.totalLength = t;
11580 this.fireEvent("datachanged", this);
11582 this.totalLength = Math.max(t, this.data.length+r.length);
11586 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11588 var e = new Roo.data.Record({});
11590 e.set(this.parent.displayField, this.parent.emptyTitle);
11591 e.set(this.parent.valueField, '');
11596 this.fireEvent("load", this, r, options, o);
11597 if(options.callback){
11598 options.callback.call(options.scope || this, r, options, true);
11604 * Loads data from a passed data block. A Reader which understands the format of the data
11605 * must have been configured in the constructor.
11606 * @param {Object} data The data block from which to read the Records. The format of the data expected
11607 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11608 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11610 loadData : function(o, append){
11611 var r = this.reader.readRecords(o);
11612 this.loadRecords(r, {add: append}, true);
11616 * Gets the number of cached records.
11618 * <em>If using paging, this may not be the total size of the dataset. If the data object
11619 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11620 * the data set size</em>
11622 getCount : function(){
11623 return this.data.length || 0;
11627 * Gets the total number of records in the dataset as returned by the server.
11629 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11630 * the dataset size</em>
11632 getTotalCount : function(){
11633 return this.totalLength || 0;
11637 * Returns the sort state of the Store as an object with two properties:
11639 field {String} The name of the field by which the Records are sorted
11640 direction {String} The sort order, "ASC" or "DESC"
11643 getSortState : function(){
11644 return this.sortInfo;
11648 applySort : function(){
11649 if(this.sortInfo && !this.remoteSort){
11650 var s = this.sortInfo, f = s.field;
11651 var st = this.fields.get(f).sortType;
11652 var fn = function(r1, r2){
11653 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11654 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11656 this.data.sort(s.direction, fn);
11657 if(this.snapshot && this.snapshot != this.data){
11658 this.snapshot.sort(s.direction, fn);
11664 * Sets the default sort column and order to be used by the next load operation.
11665 * @param {String} fieldName The name of the field to sort by.
11666 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11668 setDefaultSort : function(field, dir){
11669 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11673 * Sort the Records.
11674 * If remote sorting is used, the sort is performed on the server, and the cache is
11675 * reloaded. If local sorting is used, the cache is sorted internally.
11676 * @param {String} fieldName The name of the field to sort by.
11677 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11679 sort : function(fieldName, dir){
11680 var f = this.fields.get(fieldName);
11682 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11684 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11685 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11690 this.sortToggle[f.name] = dir;
11691 this.sortInfo = {field: f.name, direction: dir};
11692 if(!this.remoteSort){
11694 this.fireEvent("datachanged", this);
11696 this.load(this.lastOptions);
11701 * Calls the specified function for each of the Records in the cache.
11702 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11703 * Returning <em>false</em> aborts and exits the iteration.
11704 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11706 each : function(fn, scope){
11707 this.data.each(fn, scope);
11711 * Gets all records modified since the last commit. Modified records are persisted across load operations
11712 * (e.g., during paging).
11713 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11715 getModifiedRecords : function(){
11716 return this.modified;
11720 createFilterFn : function(property, value, anyMatch){
11721 if(!value.exec){ // not a regex
11722 value = String(value);
11723 if(value.length == 0){
11726 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11728 return function(r){
11729 return value.test(r.data[property]);
11734 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11735 * @param {String} property A field on your records
11736 * @param {Number} start The record index to start at (defaults to 0)
11737 * @param {Number} end The last record index to include (defaults to length - 1)
11738 * @return {Number} The sum
11740 sum : function(property, start, end){
11741 var rs = this.data.items, v = 0;
11742 start = start || 0;
11743 end = (end || end === 0) ? end : rs.length-1;
11745 for(var i = start; i <= end; i++){
11746 v += (rs[i].data[property] || 0);
11752 * Filter the records by a specified property.
11753 * @param {String} field A field on your records
11754 * @param {String/RegExp} value Either a string that the field
11755 * should start with or a RegExp to test against the field
11756 * @param {Boolean} anyMatch True to match any part not just the beginning
11758 filter : function(property, value, anyMatch){
11759 var fn = this.createFilterFn(property, value, anyMatch);
11760 return fn ? this.filterBy(fn) : this.clearFilter();
11764 * Filter by a function. The specified function will be called with each
11765 * record in this data source. If the function returns true the record is included,
11766 * otherwise it is filtered.
11767 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11768 * @param {Object} scope (optional) The scope of the function (defaults to this)
11770 filterBy : function(fn, scope){
11771 this.snapshot = this.snapshot || this.data;
11772 this.data = this.queryBy(fn, scope||this);
11773 this.fireEvent("datachanged", this);
11777 * Query the records by a specified property.
11778 * @param {String} field A field on your records
11779 * @param {String/RegExp} value Either a string that the field
11780 * should start with or a RegExp to test against the field
11781 * @param {Boolean} anyMatch True to match any part not just the beginning
11782 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11784 query : function(property, value, anyMatch){
11785 var fn = this.createFilterFn(property, value, anyMatch);
11786 return fn ? this.queryBy(fn) : this.data.clone();
11790 * Query by a function. The specified function will be called with each
11791 * record in this data source. If the function returns true the record is included
11793 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11794 * @param {Object} scope (optional) The scope of the function (defaults to this)
11795 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11797 queryBy : function(fn, scope){
11798 var data = this.snapshot || this.data;
11799 return data.filterBy(fn, scope||this);
11803 * Collects unique values for a particular dataIndex from this store.
11804 * @param {String} dataIndex The property to collect
11805 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11806 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11807 * @return {Array} An array of the unique values
11809 collect : function(dataIndex, allowNull, bypassFilter){
11810 var d = (bypassFilter === true && this.snapshot) ?
11811 this.snapshot.items : this.data.items;
11812 var v, sv, r = [], l = {};
11813 for(var i = 0, len = d.length; i < len; i++){
11814 v = d[i].data[dataIndex];
11816 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11825 * Revert to a view of the Record cache with no filtering applied.
11826 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11828 clearFilter : function(suppressEvent){
11829 if(this.snapshot && this.snapshot != this.data){
11830 this.data = this.snapshot;
11831 delete this.snapshot;
11832 if(suppressEvent !== true){
11833 this.fireEvent("datachanged", this);
11839 afterEdit : function(record){
11840 if(this.modified.indexOf(record) == -1){
11841 this.modified.push(record);
11843 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11847 afterReject : function(record){
11848 this.modified.remove(record);
11849 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11853 afterCommit : function(record){
11854 this.modified.remove(record);
11855 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11859 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11860 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11862 commitChanges : function(){
11863 var m = this.modified.slice(0);
11864 this.modified = [];
11865 for(var i = 0, len = m.length; i < len; i++){
11871 * Cancel outstanding changes on all changed records.
11873 rejectChanges : function(){
11874 var m = this.modified.slice(0);
11875 this.modified = [];
11876 for(var i = 0, len = m.length; i < len; i++){
11881 onMetaChange : function(meta, rtype, o){
11882 this.recordType = rtype;
11883 this.fields = rtype.prototype.fields;
11884 delete this.snapshot;
11885 this.sortInfo = meta.sortInfo || this.sortInfo;
11886 this.modified = [];
11887 this.fireEvent('metachange', this, this.reader.meta);
11890 moveIndex : function(data, type)
11892 var index = this.indexOf(data);
11894 var newIndex = index + type;
11898 this.insert(newIndex, data);
11903 * Ext JS Library 1.1.1
11904 * Copyright(c) 2006-2007, Ext JS, LLC.
11906 * Originally Released Under LGPL - original licence link has changed is not relivant.
11909 * <script type="text/javascript">
11913 * @class Roo.data.SimpleStore
11914 * @extends Roo.data.Store
11915 * Small helper class to make creating Stores from Array data easier.
11916 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11917 * @cfg {Array} fields An array of field definition objects, or field name strings.
11918 * @cfg {Array} data The multi-dimensional array of data
11920 * @param {Object} config
11922 Roo.data.SimpleStore = function(config){
11923 Roo.data.SimpleStore.superclass.constructor.call(this, {
11925 reader: new Roo.data.ArrayReader({
11928 Roo.data.Record.create(config.fields)
11930 proxy : new Roo.data.MemoryProxy(config.data)
11934 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11936 * Ext JS Library 1.1.1
11937 * Copyright(c) 2006-2007, Ext JS, LLC.
11939 * Originally Released Under LGPL - original licence link has changed is not relivant.
11942 * <script type="text/javascript">
11947 * @extends Roo.data.Store
11948 * @class Roo.data.JsonStore
11949 * Small helper class to make creating Stores for JSON data easier. <br/>
11951 var store = new Roo.data.JsonStore({
11952 url: 'get-images.php',
11954 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11957 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11958 * JsonReader and HttpProxy (unless inline data is provided).</b>
11959 * @cfg {Array} fields An array of field definition objects, or field name strings.
11961 * @param {Object} config
11963 Roo.data.JsonStore = function(c){
11964 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11965 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11966 reader: new Roo.data.JsonReader(c, c.fields)
11969 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11971 * Ext JS Library 1.1.1
11972 * Copyright(c) 2006-2007, Ext JS, LLC.
11974 * Originally Released Under LGPL - original licence link has changed is not relivant.
11977 * <script type="text/javascript">
11981 Roo.data.Field = function(config){
11982 if(typeof config == "string"){
11983 config = {name: config};
11985 Roo.apply(this, config);
11988 this.type = "auto";
11991 var st = Roo.data.SortTypes;
11992 // named sortTypes are supported, here we look them up
11993 if(typeof this.sortType == "string"){
11994 this.sortType = st[this.sortType];
11997 // set default sortType for strings and dates
11998 if(!this.sortType){
12001 this.sortType = st.asUCString;
12004 this.sortType = st.asDate;
12007 this.sortType = st.none;
12012 var stripRe = /[\$,%]/g;
12014 // prebuilt conversion function for this field, instead of
12015 // switching every time we're reading a value
12017 var cv, dateFormat = this.dateFormat;
12022 cv = function(v){ return v; };
12025 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12029 return v !== undefined && v !== null && v !== '' ?
12030 parseInt(String(v).replace(stripRe, ""), 10) : '';
12035 return v !== undefined && v !== null && v !== '' ?
12036 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12041 cv = function(v){ return v === true || v === "true" || v == 1; };
12048 if(v instanceof Date){
12052 if(dateFormat == "timestamp"){
12053 return new Date(v*1000);
12055 return Date.parseDate(v, dateFormat);
12057 var parsed = Date.parse(v);
12058 return parsed ? new Date(parsed) : null;
12067 Roo.data.Field.prototype = {
12075 * Ext JS Library 1.1.1
12076 * Copyright(c) 2006-2007, Ext JS, LLC.
12078 * Originally Released Under LGPL - original licence link has changed is not relivant.
12081 * <script type="text/javascript">
12084 // Base class for reading structured data from a data source. This class is intended to be
12085 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12088 * @class Roo.data.DataReader
12089 * Base class for reading structured data from a data source. This class is intended to be
12090 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12093 Roo.data.DataReader = function(meta, recordType){
12097 this.recordType = recordType instanceof Array ?
12098 Roo.data.Record.create(recordType) : recordType;
12101 Roo.data.DataReader.prototype = {
12103 * Create an empty record
12104 * @param {Object} data (optional) - overlay some values
12105 * @return {Roo.data.Record} record created.
12107 newRow : function(d) {
12109 this.recordType.prototype.fields.each(function(c) {
12111 case 'int' : da[c.name] = 0; break;
12112 case 'date' : da[c.name] = new Date(); break;
12113 case 'float' : da[c.name] = 0.0; break;
12114 case 'boolean' : da[c.name] = false; break;
12115 default : da[c.name] = ""; break;
12119 return new this.recordType(Roo.apply(da, d));
12124 * Ext JS Library 1.1.1
12125 * Copyright(c) 2006-2007, Ext JS, LLC.
12127 * Originally Released Under LGPL - original licence link has changed is not relivant.
12130 * <script type="text/javascript">
12134 * @class Roo.data.DataProxy
12135 * @extends Roo.data.Observable
12136 * This class is an abstract base class for implementations which provide retrieval of
12137 * unformatted data objects.<br>
12139 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12140 * (of the appropriate type which knows how to parse the data object) to provide a block of
12141 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12143 * Custom implementations must implement the load method as described in
12144 * {@link Roo.data.HttpProxy#load}.
12146 Roo.data.DataProxy = function(){
12149 * @event beforeload
12150 * Fires before a network request is made to retrieve a data object.
12151 * @param {Object} This DataProxy object.
12152 * @param {Object} params The params parameter to the load function.
12157 * Fires before the load method's callback is called.
12158 * @param {Object} This DataProxy object.
12159 * @param {Object} o The data object.
12160 * @param {Object} arg The callback argument object passed to the load function.
12164 * @event loadexception
12165 * Fires if an Exception occurs during data retrieval.
12166 * @param {Object} This DataProxy object.
12167 * @param {Object} o The data object.
12168 * @param {Object} arg The callback argument object passed to the load function.
12169 * @param {Object} e The Exception.
12171 loadexception : true
12173 Roo.data.DataProxy.superclass.constructor.call(this);
12176 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12179 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12183 * Ext JS Library 1.1.1
12184 * Copyright(c) 2006-2007, Ext JS, LLC.
12186 * Originally Released Under LGPL - original licence link has changed is not relivant.
12189 * <script type="text/javascript">
12192 * @class Roo.data.MemoryProxy
12193 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12194 * to the Reader when its load method is called.
12196 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12198 Roo.data.MemoryProxy = function(data){
12202 Roo.data.MemoryProxy.superclass.constructor.call(this);
12206 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12209 * Load data from the requested source (in this case an in-memory
12210 * data object passed to the constructor), read the data object into
12211 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12212 * process that block using the passed callback.
12213 * @param {Object} params This parameter is not used by the MemoryProxy class.
12214 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12215 * object into a block of Roo.data.Records.
12216 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12217 * The function must be passed <ul>
12218 * <li>The Record block object</li>
12219 * <li>The "arg" argument from the load function</li>
12220 * <li>A boolean success indicator</li>
12222 * @param {Object} scope The scope in which to call the callback
12223 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12225 load : function(params, reader, callback, scope, arg){
12226 params = params || {};
12229 result = reader.readRecords(this.data);
12231 this.fireEvent("loadexception", this, arg, null, e);
12232 callback.call(scope, null, arg, false);
12235 callback.call(scope, result, arg, true);
12239 update : function(params, records){
12244 * Ext JS Library 1.1.1
12245 * Copyright(c) 2006-2007, Ext JS, LLC.
12247 * Originally Released Under LGPL - original licence link has changed is not relivant.
12250 * <script type="text/javascript">
12253 * @class Roo.data.HttpProxy
12254 * @extends Roo.data.DataProxy
12255 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12256 * configured to reference a certain URL.<br><br>
12258 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12259 * from which the running page was served.<br><br>
12261 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12263 * Be aware that to enable the browser to parse an XML document, the server must set
12264 * the Content-Type header in the HTTP response to "text/xml".
12266 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12267 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12268 * will be used to make the request.
12270 Roo.data.HttpProxy = function(conn){
12271 Roo.data.HttpProxy.superclass.constructor.call(this);
12272 // is conn a conn config or a real conn?
12274 this.useAjax = !conn || !conn.events;
12278 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12279 // thse are take from connection...
12282 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12285 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12286 * extra parameters to each request made by this object. (defaults to undefined)
12289 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12290 * to each request made by this object. (defaults to undefined)
12293 * @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)
12296 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12299 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12305 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12309 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12310 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12311 * a finer-grained basis than the DataProxy events.
12313 getConnection : function(){
12314 return this.useAjax ? Roo.Ajax : this.conn;
12318 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12319 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12320 * process that block using the passed callback.
12321 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12322 * for the request to the remote server.
12323 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12324 * object into a block of Roo.data.Records.
12325 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12326 * The function must be passed <ul>
12327 * <li>The Record block object</li>
12328 * <li>The "arg" argument from the load function</li>
12329 * <li>A boolean success indicator</li>
12331 * @param {Object} scope The scope in which to call the callback
12332 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12334 load : function(params, reader, callback, scope, arg){
12335 if(this.fireEvent("beforeload", this, params) !== false){
12337 params : params || {},
12339 callback : callback,
12344 callback : this.loadResponse,
12348 Roo.applyIf(o, this.conn);
12349 if(this.activeRequest){
12350 Roo.Ajax.abort(this.activeRequest);
12352 this.activeRequest = Roo.Ajax.request(o);
12354 this.conn.request(o);
12357 callback.call(scope||this, null, arg, false);
12362 loadResponse : function(o, success, response){
12363 delete this.activeRequest;
12365 this.fireEvent("loadexception", this, o, response);
12366 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12371 result = o.reader.read(response);
12373 this.fireEvent("loadexception", this, o, response, e);
12374 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12378 this.fireEvent("load", this, o, o.request.arg);
12379 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12383 update : function(dataSet){
12388 updateResponse : function(dataSet){
12393 * Ext JS Library 1.1.1
12394 * Copyright(c) 2006-2007, Ext JS, LLC.
12396 * Originally Released Under LGPL - original licence link has changed is not relivant.
12399 * <script type="text/javascript">
12403 * @class Roo.data.ScriptTagProxy
12404 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12405 * other than the originating domain of the running page.<br><br>
12407 * <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
12408 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12410 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12411 * source code that is used as the source inside a <script> tag.<br><br>
12413 * In order for the browser to process the returned data, the server must wrap the data object
12414 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12415 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12416 * depending on whether the callback name was passed:
12419 boolean scriptTag = false;
12420 String cb = request.getParameter("callback");
12423 response.setContentType("text/javascript");
12425 response.setContentType("application/x-json");
12427 Writer out = response.getWriter();
12429 out.write(cb + "(");
12431 out.print(dataBlock.toJsonString());
12438 * @param {Object} config A configuration object.
12440 Roo.data.ScriptTagProxy = function(config){
12441 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12442 Roo.apply(this, config);
12443 this.head = document.getElementsByTagName("head")[0];
12446 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12448 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12450 * @cfg {String} url The URL from which to request the data object.
12453 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12457 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12458 * the server the name of the callback function set up by the load call to process the returned data object.
12459 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12460 * javascript output which calls this named function passing the data object as its only parameter.
12462 callbackParam : "callback",
12464 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12465 * name to the request.
12470 * Load data from the configured URL, read the data object into
12471 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12472 * process that block using the passed callback.
12473 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12474 * for the request to the remote server.
12475 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12476 * object into a block of Roo.data.Records.
12477 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12478 * The function must be passed <ul>
12479 * <li>The Record block object</li>
12480 * <li>The "arg" argument from the load function</li>
12481 * <li>A boolean success indicator</li>
12483 * @param {Object} scope The scope in which to call the callback
12484 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12486 load : function(params, reader, callback, scope, arg){
12487 if(this.fireEvent("beforeload", this, params) !== false){
12489 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12491 var url = this.url;
12492 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12494 url += "&_dc=" + (new Date().getTime());
12496 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12499 cb : "stcCallback"+transId,
12500 scriptId : "stcScript"+transId,
12504 callback : callback,
12510 window[trans.cb] = function(o){
12511 conn.handleResponse(o, trans);
12514 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12516 if(this.autoAbort !== false){
12520 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12522 var script = document.createElement("script");
12523 script.setAttribute("src", url);
12524 script.setAttribute("type", "text/javascript");
12525 script.setAttribute("id", trans.scriptId);
12526 this.head.appendChild(script);
12528 this.trans = trans;
12530 callback.call(scope||this, null, arg, false);
12535 isLoading : function(){
12536 return this.trans ? true : false;
12540 * Abort the current server request.
12542 abort : function(){
12543 if(this.isLoading()){
12544 this.destroyTrans(this.trans);
12549 destroyTrans : function(trans, isLoaded){
12550 this.head.removeChild(document.getElementById(trans.scriptId));
12551 clearTimeout(trans.timeoutId);
12553 window[trans.cb] = undefined;
12555 delete window[trans.cb];
12558 // if hasn't been loaded, wait for load to remove it to prevent script error
12559 window[trans.cb] = function(){
12560 window[trans.cb] = undefined;
12562 delete window[trans.cb];
12569 handleResponse : function(o, trans){
12570 this.trans = false;
12571 this.destroyTrans(trans, true);
12574 result = trans.reader.readRecords(o);
12576 this.fireEvent("loadexception", this, o, trans.arg, e);
12577 trans.callback.call(trans.scope||window, null, trans.arg, false);
12580 this.fireEvent("load", this, o, trans.arg);
12581 trans.callback.call(trans.scope||window, result, trans.arg, true);
12585 handleFailure : function(trans){
12586 this.trans = false;
12587 this.destroyTrans(trans, false);
12588 this.fireEvent("loadexception", this, null, trans.arg);
12589 trans.callback.call(trans.scope||window, null, trans.arg, false);
12593 * Ext JS Library 1.1.1
12594 * Copyright(c) 2006-2007, Ext JS, LLC.
12596 * Originally Released Under LGPL - original licence link has changed is not relivant.
12599 * <script type="text/javascript">
12603 * @class Roo.data.JsonReader
12604 * @extends Roo.data.DataReader
12605 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12606 * based on mappings in a provided Roo.data.Record constructor.
12608 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12609 * in the reply previously.
12614 var RecordDef = Roo.data.Record.create([
12615 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12616 {name: 'occupation'} // This field will use "occupation" as the mapping.
12618 var myReader = new Roo.data.JsonReader({
12619 totalProperty: "results", // The property which contains the total dataset size (optional)
12620 root: "rows", // The property which contains an Array of row objects
12621 id: "id" // The property within each row object that provides an ID for the record (optional)
12625 * This would consume a JSON file like this:
12627 { 'results': 2, 'rows': [
12628 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12629 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12632 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12633 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12634 * paged from the remote server.
12635 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12636 * @cfg {String} root name of the property which contains the Array of row objects.
12637 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12638 * @cfg {Array} fields Array of field definition objects
12640 * Create a new JsonReader
12641 * @param {Object} meta Metadata configuration options
12642 * @param {Object} recordType Either an Array of field definition objects,
12643 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12645 Roo.data.JsonReader = function(meta, recordType){
12648 // set some defaults:
12649 Roo.applyIf(meta, {
12650 totalProperty: 'total',
12651 successProperty : 'success',
12656 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12658 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12661 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12662 * Used by Store query builder to append _requestMeta to params.
12665 metaFromRemote : false,
12667 * This method is only used by a DataProxy which has retrieved data from a remote server.
12668 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12669 * @return {Object} data A data block which is used by an Roo.data.Store object as
12670 * a cache of Roo.data.Records.
12672 read : function(response){
12673 var json = response.responseText;
12675 var o = /* eval:var:o */ eval("("+json+")");
12677 throw {message: "JsonReader.read: Json object not found"};
12683 this.metaFromRemote = true;
12684 this.meta = o.metaData;
12685 this.recordType = Roo.data.Record.create(o.metaData.fields);
12686 this.onMetaChange(this.meta, this.recordType, o);
12688 return this.readRecords(o);
12691 // private function a store will implement
12692 onMetaChange : function(meta, recordType, o){
12699 simpleAccess: function(obj, subsc) {
12706 getJsonAccessor: function(){
12708 return function(expr) {
12710 return(re.test(expr))
12711 ? new Function("obj", "return obj." + expr)
12716 return Roo.emptyFn;
12721 * Create a data block containing Roo.data.Records from an XML document.
12722 * @param {Object} o An object which contains an Array of row objects in the property specified
12723 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12724 * which contains the total size of the dataset.
12725 * @return {Object} data A data block which is used by an Roo.data.Store object as
12726 * a cache of Roo.data.Records.
12728 readRecords : function(o){
12730 * After any data loads, the raw JSON data is available for further custom processing.
12734 var s = this.meta, Record = this.recordType,
12735 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12737 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12739 if(s.totalProperty) {
12740 this.getTotal = this.getJsonAccessor(s.totalProperty);
12742 if(s.successProperty) {
12743 this.getSuccess = this.getJsonAccessor(s.successProperty);
12745 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12747 var g = this.getJsonAccessor(s.id);
12748 this.getId = function(rec) {
12750 return (r === undefined || r === "") ? null : r;
12753 this.getId = function(){return null;};
12756 for(var jj = 0; jj < fl; jj++){
12758 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12759 this.ef[jj] = this.getJsonAccessor(map);
12763 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12764 if(s.totalProperty){
12765 var vt = parseInt(this.getTotal(o), 10);
12770 if(s.successProperty){
12771 var vs = this.getSuccess(o);
12772 if(vs === false || vs === 'false'){
12777 for(var i = 0; i < c; i++){
12780 var id = this.getId(n);
12781 for(var j = 0; j < fl; j++){
12783 var v = this.ef[j](n);
12785 Roo.log('missing convert for ' + f.name);
12789 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12791 var record = new Record(values, id);
12793 records[i] = record;
12799 totalRecords : totalRecords
12804 * Ext JS Library 1.1.1
12805 * Copyright(c) 2006-2007, Ext JS, LLC.
12807 * Originally Released Under LGPL - original licence link has changed is not relivant.
12810 * <script type="text/javascript">
12814 * @class Roo.data.ArrayReader
12815 * @extends Roo.data.DataReader
12816 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12817 * Each element of that Array represents a row of data fields. The
12818 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12819 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12823 var RecordDef = Roo.data.Record.create([
12824 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12825 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12827 var myReader = new Roo.data.ArrayReader({
12828 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12832 * This would consume an Array like this:
12834 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12836 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12838 * Create a new JsonReader
12839 * @param {Object} meta Metadata configuration options.
12840 * @param {Object} recordType Either an Array of field definition objects
12841 * as specified to {@link Roo.data.Record#create},
12842 * or an {@link Roo.data.Record} object
12843 * created using {@link Roo.data.Record#create}.
12845 Roo.data.ArrayReader = function(meta, recordType){
12846 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12849 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12851 * Create a data block containing Roo.data.Records from an XML document.
12852 * @param {Object} o An Array of row objects which represents the dataset.
12853 * @return {Object} data A data block which is used by an Roo.data.Store object as
12854 * a cache of Roo.data.Records.
12856 readRecords : function(o){
12857 var sid = this.meta ? this.meta.id : null;
12858 var recordType = this.recordType, fields = recordType.prototype.fields;
12861 for(var i = 0; i < root.length; i++){
12864 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12865 for(var j = 0, jlen = fields.length; j < jlen; j++){
12866 var f = fields.items[j];
12867 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12868 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12870 values[f.name] = v;
12872 var record = new recordType(values, id);
12874 records[records.length] = record;
12878 totalRecords : records.length
12887 * @class Roo.bootstrap.ComboBox
12888 * @extends Roo.bootstrap.TriggerField
12889 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12890 * @cfg {Boolean} append (true|false) default false
12891 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12892 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12893 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12894 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12895 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12896 * @cfg {Boolean} animate default true
12897 * @cfg {Boolean} emptyResultText only for touch device
12898 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12899 * @cfg {String} emptyTitle default ''
12901 * Create a new ComboBox.
12902 * @param {Object} config Configuration options
12904 Roo.bootstrap.ComboBox = function(config){
12905 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12909 * Fires when the dropdown list is expanded
12910 * @param {Roo.bootstrap.ComboBox} combo This combo box
12915 * Fires when the dropdown list is collapsed
12916 * @param {Roo.bootstrap.ComboBox} combo This combo box
12920 * @event beforeselect
12921 * Fires before a list item is selected. Return false to cancel the selection.
12922 * @param {Roo.bootstrap.ComboBox} combo This combo box
12923 * @param {Roo.data.Record} record The data record returned from the underlying store
12924 * @param {Number} index The index of the selected item in the dropdown list
12926 'beforeselect' : true,
12929 * Fires when a list item is selected
12930 * @param {Roo.bootstrap.ComboBox} combo This combo box
12931 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12932 * @param {Number} index The index of the selected item in the dropdown list
12936 * @event beforequery
12937 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12938 * The event object passed has these properties:
12939 * @param {Roo.bootstrap.ComboBox} combo This combo box
12940 * @param {String} query The query
12941 * @param {Boolean} forceAll true to force "all" query
12942 * @param {Boolean} cancel true to cancel the query
12943 * @param {Object} e The query event object
12945 'beforequery': true,
12948 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12949 * @param {Roo.bootstrap.ComboBox} combo This combo box
12954 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12955 * @param {Roo.bootstrap.ComboBox} combo This combo box
12956 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12961 * Fires when the remove value from the combobox array
12962 * @param {Roo.bootstrap.ComboBox} combo This combo box
12966 * @event afterremove
12967 * Fires when the remove value from the combobox array
12968 * @param {Roo.bootstrap.ComboBox} combo This combo box
12970 'afterremove' : true,
12972 * @event specialfilter
12973 * Fires when specialfilter
12974 * @param {Roo.bootstrap.ComboBox} combo This combo box
12976 'specialfilter' : true,
12979 * Fires when tick the element
12980 * @param {Roo.bootstrap.ComboBox} combo This combo box
12984 * @event touchviewdisplay
12985 * Fires when touch view require special display (default is using displayField)
12986 * @param {Roo.bootstrap.ComboBox} combo This combo box
12987 * @param {Object} cfg set html .
12989 'touchviewdisplay' : true
12994 this.tickItems = [];
12996 this.selectedIndex = -1;
12997 if(this.mode == 'local'){
12998 if(config.queryDelay === undefined){
12999 this.queryDelay = 10;
13001 if(config.minChars === undefined){
13007 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13010 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13011 * rendering into an Roo.Editor, defaults to false)
13014 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13015 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13018 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13021 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13022 * the dropdown list (defaults to undefined, with no header element)
13026 * @cfg {String/Roo.Template} tpl The template to use to render the output
13030 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13032 listWidth: undefined,
13034 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13035 * mode = 'remote' or 'text' if mode = 'local')
13037 displayField: undefined,
13040 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13041 * mode = 'remote' or 'value' if mode = 'local').
13042 * Note: use of a valueField requires the user make a selection
13043 * in order for a value to be mapped.
13045 valueField: undefined,
13047 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13052 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13053 * field's data value (defaults to the underlying DOM element's name)
13055 hiddenName: undefined,
13057 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13061 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13063 selectedClass: 'active',
13066 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13070 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13071 * anchor positions (defaults to 'tl-bl')
13073 listAlign: 'tl-bl?',
13075 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13079 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13080 * query specified by the allQuery config option (defaults to 'query')
13082 triggerAction: 'query',
13084 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13085 * (defaults to 4, does not apply if editable = false)
13089 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13090 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13094 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13095 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13099 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13100 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13104 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13105 * when editable = true (defaults to false)
13107 selectOnFocus:false,
13109 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13111 queryParam: 'query',
13113 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13114 * when mode = 'remote' (defaults to 'Loading...')
13116 loadingText: 'Loading...',
13118 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13122 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13126 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13127 * traditional select (defaults to true)
13131 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13135 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13139 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13140 * listWidth has a higher value)
13144 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13145 * allow the user to set arbitrary text into the field (defaults to false)
13147 forceSelection:false,
13149 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13150 * if typeAhead = true (defaults to 250)
13152 typeAheadDelay : 250,
13154 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13155 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13157 valueNotFoundText : undefined,
13159 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13161 blockFocus : false,
13164 * @cfg {Boolean} disableClear Disable showing of clear button.
13166 disableClear : false,
13168 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13170 alwaysQuery : false,
13173 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13178 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13180 invalidClass : "has-warning",
13183 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13185 validClass : "has-success",
13188 * @cfg {Boolean} specialFilter (true|false) special filter default false
13190 specialFilter : false,
13193 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13195 mobileTouchView : true,
13198 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13200 useNativeIOS : false,
13203 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13205 mobile_restrict_height : false,
13207 ios_options : false,
13219 btnPosition : 'right',
13220 triggerList : true,
13221 showToggleBtn : true,
13223 emptyResultText: 'Empty',
13224 triggerText : 'Select',
13227 // element that contains real text value.. (when hidden is used..)
13229 getAutoCreate : function()
13234 * Render classic select for iso
13237 if(Roo.isIOS && this.useNativeIOS){
13238 cfg = this.getAutoCreateNativeIOS();
13246 if(Roo.isTouch && this.mobileTouchView){
13247 cfg = this.getAutoCreateTouchView();
13254 if(!this.tickable){
13255 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13260 * ComboBox with tickable selections
13263 var align = this.labelAlign || this.parentLabelAlign();
13266 cls : 'form-group roo-combobox-tickable' //input-group
13269 var btn_text_select = '';
13270 var btn_text_done = '';
13271 var btn_text_cancel = '';
13273 if (this.btn_text_show) {
13274 btn_text_select = 'Select';
13275 btn_text_done = 'Done';
13276 btn_text_cancel = 'Cancel';
13281 cls : 'tickable-buttons',
13286 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13287 //html : this.triggerText
13288 html: btn_text_select
13294 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13296 html: btn_text_done
13302 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13304 html: btn_text_cancel
13310 buttons.cn.unshift({
13312 cls: 'roo-select2-search-field-input'
13318 Roo.each(buttons.cn, function(c){
13320 c.cls += ' btn-' + _this.size;
13323 if (_this.disabled) {
13334 cls: 'form-hidden-field'
13338 cls: 'roo-select2-choices',
13342 cls: 'roo-select2-search-field',
13353 cls: 'roo-select2-container input-group roo-select2-container-multi',
13358 // cls: 'typeahead typeahead-long dropdown-menu',
13359 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13364 if(this.hasFeedback && !this.allowBlank){
13368 cls: 'glyphicon form-control-feedback'
13371 combobox.cn.push(feedback);
13376 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13377 tooltip : 'This field is required'
13379 if (Roo.bootstrap.version == 4) {
13382 style : 'display:none'
13385 if (align ==='left' && this.fieldLabel.length) {
13387 cfg.cls += ' roo-form-group-label-left row';
13394 cls : 'control-label col-form-label',
13395 html : this.fieldLabel
13407 var labelCfg = cfg.cn[1];
13408 var contentCfg = cfg.cn[2];
13411 if(this.indicatorpos == 'right'){
13417 cls : 'control-label col-form-label',
13421 html : this.fieldLabel
13437 labelCfg = cfg.cn[0];
13438 contentCfg = cfg.cn[1];
13442 if(this.labelWidth > 12){
13443 labelCfg.style = "width: " + this.labelWidth + 'px';
13446 if(this.labelWidth < 13 && this.labelmd == 0){
13447 this.labelmd = this.labelWidth;
13450 if(this.labellg > 0){
13451 labelCfg.cls += ' col-lg-' + this.labellg;
13452 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13455 if(this.labelmd > 0){
13456 labelCfg.cls += ' col-md-' + this.labelmd;
13457 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13460 if(this.labelsm > 0){
13461 labelCfg.cls += ' col-sm-' + this.labelsm;
13462 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13465 if(this.labelxs > 0){
13466 labelCfg.cls += ' col-xs-' + this.labelxs;
13467 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13471 } else if ( this.fieldLabel.length) {
13472 // Roo.log(" label");
13477 //cls : 'input-group-addon',
13478 html : this.fieldLabel
13483 if(this.indicatorpos == 'right'){
13487 //cls : 'input-group-addon',
13488 html : this.fieldLabel
13498 // Roo.log(" no label && no align");
13505 ['xs','sm','md','lg'].map(function(size){
13506 if (settings[size]) {
13507 cfg.cls += ' col-' + size + '-' + settings[size];
13515 _initEventsCalled : false,
13518 initEvents: function()
13520 if (this._initEventsCalled) { // as we call render... prevent looping...
13523 this._initEventsCalled = true;
13526 throw "can not find store for combo";
13529 this.indicator = this.indicatorEl();
13531 this.store = Roo.factory(this.store, Roo.data);
13532 this.store.parent = this;
13534 // if we are building from html. then this element is so complex, that we can not really
13535 // use the rendered HTML.
13536 // so we have to trash and replace the previous code.
13537 if (Roo.XComponent.build_from_html) {
13538 // remove this element....
13539 var e = this.el.dom, k=0;
13540 while (e ) { e = e.previousSibling; ++k;}
13545 this.rendered = false;
13547 this.render(this.parent().getChildContainer(true), k);
13550 if(Roo.isIOS && this.useNativeIOS){
13551 this.initIOSView();
13559 if(Roo.isTouch && this.mobileTouchView){
13560 this.initTouchView();
13565 this.initTickableEvents();
13569 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13571 if(this.hiddenName){
13573 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13575 this.hiddenField.dom.value =
13576 this.hiddenValue !== undefined ? this.hiddenValue :
13577 this.value !== undefined ? this.value : '';
13579 // prevent input submission
13580 this.el.dom.removeAttribute('name');
13581 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13586 // this.el.dom.setAttribute('autocomplete', 'off');
13589 var cls = 'x-combo-list';
13591 //this.list = new Roo.Layer({
13592 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13598 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13599 _this.list.setWidth(lw);
13602 this.list.on('mouseover', this.onViewOver, this);
13603 this.list.on('mousemove', this.onViewMove, this);
13604 this.list.on('scroll', this.onViewScroll, this);
13607 this.list.swallowEvent('mousewheel');
13608 this.assetHeight = 0;
13611 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13612 this.assetHeight += this.header.getHeight();
13615 this.innerList = this.list.createChild({cls:cls+'-inner'});
13616 this.innerList.on('mouseover', this.onViewOver, this);
13617 this.innerList.on('mousemove', this.onViewMove, this);
13618 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13620 if(this.allowBlank && !this.pageSize && !this.disableClear){
13621 this.footer = this.list.createChild({cls:cls+'-ft'});
13622 this.pageTb = new Roo.Toolbar(this.footer);
13626 this.footer = this.list.createChild({cls:cls+'-ft'});
13627 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13628 {pageSize: this.pageSize});
13632 if (this.pageTb && this.allowBlank && !this.disableClear) {
13634 this.pageTb.add(new Roo.Toolbar.Fill(), {
13635 cls: 'x-btn-icon x-btn-clear',
13637 handler: function()
13640 _this.clearValue();
13641 _this.onSelect(false, -1);
13646 this.assetHeight += this.footer.getHeight();
13651 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13654 this.view = new Roo.View(this.list, this.tpl, {
13655 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13657 //this.view.wrapEl.setDisplayed(false);
13658 this.view.on('click', this.onViewClick, this);
13661 this.store.on('beforeload', this.onBeforeLoad, this);
13662 this.store.on('load', this.onLoad, this);
13663 this.store.on('loadexception', this.onLoadException, this);
13665 if(this.resizable){
13666 this.resizer = new Roo.Resizable(this.list, {
13667 pinned:true, handles:'se'
13669 this.resizer.on('resize', function(r, w, h){
13670 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13671 this.listWidth = w;
13672 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13673 this.restrictHeight();
13675 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13678 if(!this.editable){
13679 this.editable = true;
13680 this.setEditable(false);
13685 if (typeof(this.events.add.listeners) != 'undefined') {
13687 this.addicon = this.wrap.createChild(
13688 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13690 this.addicon.on('click', function(e) {
13691 this.fireEvent('add', this);
13694 if (typeof(this.events.edit.listeners) != 'undefined') {
13696 this.editicon = this.wrap.createChild(
13697 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13698 if (this.addicon) {
13699 this.editicon.setStyle('margin-left', '40px');
13701 this.editicon.on('click', function(e) {
13703 // we fire even if inothing is selected..
13704 this.fireEvent('edit', this, this.lastData );
13710 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13711 "up" : function(e){
13712 this.inKeyMode = true;
13716 "down" : function(e){
13717 if(!this.isExpanded()){
13718 this.onTriggerClick();
13720 this.inKeyMode = true;
13725 "enter" : function(e){
13726 // this.onViewClick();
13730 if(this.fireEvent("specialkey", this, e)){
13731 this.onViewClick(false);
13737 "esc" : function(e){
13741 "tab" : function(e){
13744 if(this.fireEvent("specialkey", this, e)){
13745 this.onViewClick(false);
13753 doRelay : function(foo, bar, hname){
13754 if(hname == 'down' || this.scope.isExpanded()){
13755 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13764 this.queryDelay = Math.max(this.queryDelay || 10,
13765 this.mode == 'local' ? 10 : 250);
13768 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13770 if(this.typeAhead){
13771 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13773 if(this.editable !== false){
13774 this.inputEl().on("keyup", this.onKeyUp, this);
13776 if(this.forceSelection){
13777 this.inputEl().on('blur', this.doForce, this);
13781 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13782 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13786 initTickableEvents: function()
13790 if(this.hiddenName){
13792 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13794 this.hiddenField.dom.value =
13795 this.hiddenValue !== undefined ? this.hiddenValue :
13796 this.value !== undefined ? this.value : '';
13798 // prevent input submission
13799 this.el.dom.removeAttribute('name');
13800 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13805 // this.list = this.el.select('ul.dropdown-menu',true).first();
13807 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13808 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13809 if(this.triggerList){
13810 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13813 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13814 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13816 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13817 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13819 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13820 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13822 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13823 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13824 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13827 this.cancelBtn.hide();
13832 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13833 _this.list.setWidth(lw);
13836 this.list.on('mouseover', this.onViewOver, this);
13837 this.list.on('mousemove', this.onViewMove, this);
13839 this.list.on('scroll', this.onViewScroll, this);
13842 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13843 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13846 this.view = new Roo.View(this.list, this.tpl, {
13851 selectedClass: this.selectedClass
13854 //this.view.wrapEl.setDisplayed(false);
13855 this.view.on('click', this.onViewClick, this);
13859 this.store.on('beforeload', this.onBeforeLoad, this);
13860 this.store.on('load', this.onLoad, this);
13861 this.store.on('loadexception', this.onLoadException, this);
13864 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13865 "up" : function(e){
13866 this.inKeyMode = true;
13870 "down" : function(e){
13871 this.inKeyMode = true;
13875 "enter" : function(e){
13876 if(this.fireEvent("specialkey", this, e)){
13877 this.onViewClick(false);
13883 "esc" : function(e){
13884 this.onTickableFooterButtonClick(e, false, false);
13887 "tab" : function(e){
13888 this.fireEvent("specialkey", this, e);
13890 this.onTickableFooterButtonClick(e, false, false);
13897 doRelay : function(e, fn, key){
13898 if(this.scope.isExpanded()){
13899 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13908 this.queryDelay = Math.max(this.queryDelay || 10,
13909 this.mode == 'local' ? 10 : 250);
13912 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13914 if(this.typeAhead){
13915 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13918 if(this.editable !== false){
13919 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13922 this.indicator = this.indicatorEl();
13924 if(this.indicator){
13925 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13926 this.indicator.hide();
13931 onDestroy : function(){
13933 this.view.setStore(null);
13934 this.view.el.removeAllListeners();
13935 this.view.el.remove();
13936 this.view.purgeListeners();
13939 this.list.dom.innerHTML = '';
13943 this.store.un('beforeload', this.onBeforeLoad, this);
13944 this.store.un('load', this.onLoad, this);
13945 this.store.un('loadexception', this.onLoadException, this);
13947 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13951 fireKey : function(e){
13952 if(e.isNavKeyPress() && !this.list.isVisible()){
13953 this.fireEvent("specialkey", this, e);
13958 onResize: function(w, h){
13959 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13961 // if(typeof w != 'number'){
13962 // // we do not handle it!?!?
13965 // var tw = this.trigger.getWidth();
13966 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13967 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13969 // this.inputEl().setWidth( this.adjustWidth('input', x));
13971 // //this.trigger.setStyle('left', x+'px');
13973 // if(this.list && this.listWidth === undefined){
13974 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13975 // this.list.setWidth(lw);
13976 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13984 * Allow or prevent the user from directly editing the field text. If false is passed,
13985 * the user will only be able to select from the items defined in the dropdown list. This method
13986 * is the runtime equivalent of setting the 'editable' config option at config time.
13987 * @param {Boolean} value True to allow the user to directly edit the field text
13989 setEditable : function(value){
13990 if(value == this.editable){
13993 this.editable = value;
13995 this.inputEl().dom.setAttribute('readOnly', true);
13996 this.inputEl().on('mousedown', this.onTriggerClick, this);
13997 this.inputEl().addClass('x-combo-noedit');
13999 this.inputEl().dom.setAttribute('readOnly', false);
14000 this.inputEl().un('mousedown', this.onTriggerClick, this);
14001 this.inputEl().removeClass('x-combo-noedit');
14007 onBeforeLoad : function(combo,opts){
14008 if(!this.hasFocus){
14012 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14014 this.restrictHeight();
14015 this.selectedIndex = -1;
14019 onLoad : function(){
14021 this.hasQuery = false;
14023 if(!this.hasFocus){
14027 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14028 this.loading.hide();
14031 if(this.store.getCount() > 0){
14034 this.restrictHeight();
14035 if(this.lastQuery == this.allQuery){
14036 if(this.editable && !this.tickable){
14037 this.inputEl().dom.select();
14041 !this.selectByValue(this.value, true) &&
14044 !this.store.lastOptions ||
14045 typeof(this.store.lastOptions.add) == 'undefined' ||
14046 this.store.lastOptions.add != true
14049 this.select(0, true);
14052 if(this.autoFocus){
14055 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14056 this.taTask.delay(this.typeAheadDelay);
14060 this.onEmptyResults();
14066 onLoadException : function()
14068 this.hasQuery = false;
14070 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14071 this.loading.hide();
14074 if(this.tickable && this.editable){
14079 // only causes errors at present
14080 //Roo.log(this.store.reader.jsonData);
14081 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14083 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14089 onTypeAhead : function(){
14090 if(this.store.getCount() > 0){
14091 var r = this.store.getAt(0);
14092 var newValue = r.data[this.displayField];
14093 var len = newValue.length;
14094 var selStart = this.getRawValue().length;
14096 if(selStart != len){
14097 this.setRawValue(newValue);
14098 this.selectText(selStart, newValue.length);
14104 onSelect : function(record, index){
14106 if(this.fireEvent('beforeselect', this, record, index) !== false){
14108 this.setFromData(index > -1 ? record.data : false);
14111 this.fireEvent('select', this, record, index);
14116 * Returns the currently selected field value or empty string if no value is set.
14117 * @return {String} value The selected value
14119 getValue : function()
14121 if(Roo.isIOS && this.useNativeIOS){
14122 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14126 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14129 if(this.valueField){
14130 return typeof this.value != 'undefined' ? this.value : '';
14132 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14136 getRawValue : function()
14138 if(Roo.isIOS && this.useNativeIOS){
14139 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14142 var v = this.inputEl().getValue();
14148 * Clears any text/value currently set in the field
14150 clearValue : function(){
14152 if(this.hiddenField){
14153 this.hiddenField.dom.value = '';
14156 this.setRawValue('');
14157 this.lastSelectionText = '';
14158 this.lastData = false;
14160 var close = this.closeTriggerEl();
14171 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14172 * will be displayed in the field. If the value does not match the data value of an existing item,
14173 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14174 * Otherwise the field will be blank (although the value will still be set).
14175 * @param {String} value The value to match
14177 setValue : function(v)
14179 if(Roo.isIOS && this.useNativeIOS){
14180 this.setIOSValue(v);
14190 if(this.valueField){
14191 var r = this.findRecord(this.valueField, v);
14193 text = r.data[this.displayField];
14194 }else if(this.valueNotFoundText !== undefined){
14195 text = this.valueNotFoundText;
14198 this.lastSelectionText = text;
14199 if(this.hiddenField){
14200 this.hiddenField.dom.value = v;
14202 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14205 var close = this.closeTriggerEl();
14208 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14214 * @property {Object} the last set data for the element
14219 * Sets the value of the field based on a object which is related to the record format for the store.
14220 * @param {Object} value the value to set as. or false on reset?
14222 setFromData : function(o){
14229 var dv = ''; // display value
14230 var vv = ''; // value value..
14232 if (this.displayField) {
14233 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14235 // this is an error condition!!!
14236 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14239 if(this.valueField){
14240 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14243 var close = this.closeTriggerEl();
14246 if(dv.length || vv * 1 > 0){
14248 this.blockFocus=true;
14254 if(this.hiddenField){
14255 this.hiddenField.dom.value = vv;
14257 this.lastSelectionText = dv;
14258 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14262 // no hidden field.. - we store the value in 'value', but still display
14263 // display field!!!!
14264 this.lastSelectionText = dv;
14265 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14272 reset : function(){
14273 // overridden so that last data is reset..
14280 this.setValue(this.originalValue);
14281 //this.clearInvalid();
14282 this.lastData = false;
14284 this.view.clearSelections();
14290 findRecord : function(prop, value){
14292 if(this.store.getCount() > 0){
14293 this.store.each(function(r){
14294 if(r.data[prop] == value){
14304 getName: function()
14306 // returns hidden if it's set..
14307 if (!this.rendered) {return ''};
14308 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14312 onViewMove : function(e, t){
14313 this.inKeyMode = false;
14317 onViewOver : function(e, t){
14318 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14321 var item = this.view.findItemFromChild(t);
14324 var index = this.view.indexOf(item);
14325 this.select(index, false);
14330 onViewClick : function(view, doFocus, el, e)
14332 var index = this.view.getSelectedIndexes()[0];
14334 var r = this.store.getAt(index);
14338 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14345 Roo.each(this.tickItems, function(v,k){
14347 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14349 _this.tickItems.splice(k, 1);
14351 if(typeof(e) == 'undefined' && view == false){
14352 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14364 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14365 this.tickItems.push(r.data);
14368 if(typeof(e) == 'undefined' && view == false){
14369 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14376 this.onSelect(r, index);
14378 if(doFocus !== false && !this.blockFocus){
14379 this.inputEl().focus();
14384 restrictHeight : function(){
14385 //this.innerList.dom.style.height = '';
14386 //var inner = this.innerList.dom;
14387 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14388 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14389 //this.list.beginUpdate();
14390 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14391 this.list.alignTo(this.inputEl(), this.listAlign);
14392 this.list.alignTo(this.inputEl(), this.listAlign);
14393 //this.list.endUpdate();
14397 onEmptyResults : function(){
14399 if(this.tickable && this.editable){
14400 this.hasFocus = false;
14401 this.restrictHeight();
14409 * Returns true if the dropdown list is expanded, else false.
14411 isExpanded : function(){
14412 return this.list.isVisible();
14416 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14417 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14418 * @param {String} value The data value of the item to select
14419 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14420 * selected item if it is not currently in view (defaults to true)
14421 * @return {Boolean} True if the value matched an item in the list, else false
14423 selectByValue : function(v, scrollIntoView){
14424 if(v !== undefined && v !== null){
14425 var r = this.findRecord(this.valueField || this.displayField, v);
14427 this.select(this.store.indexOf(r), scrollIntoView);
14435 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14436 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14437 * @param {Number} index The zero-based index of the list item to select
14438 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14439 * selected item if it is not currently in view (defaults to true)
14441 select : function(index, scrollIntoView){
14442 this.selectedIndex = index;
14443 this.view.select(index);
14444 if(scrollIntoView !== false){
14445 var el = this.view.getNode(index);
14447 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14450 this.list.scrollChildIntoView(el, false);
14456 selectNext : function(){
14457 var ct = this.store.getCount();
14459 if(this.selectedIndex == -1){
14461 }else if(this.selectedIndex < ct-1){
14462 this.select(this.selectedIndex+1);
14468 selectPrev : function(){
14469 var ct = this.store.getCount();
14471 if(this.selectedIndex == -1){
14473 }else if(this.selectedIndex != 0){
14474 this.select(this.selectedIndex-1);
14480 onKeyUp : function(e){
14481 if(this.editable !== false && !e.isSpecialKey()){
14482 this.lastKey = e.getKey();
14483 this.dqTask.delay(this.queryDelay);
14488 validateBlur : function(){
14489 return !this.list || !this.list.isVisible();
14493 initQuery : function(){
14495 var v = this.getRawValue();
14497 if(this.tickable && this.editable){
14498 v = this.tickableInputEl().getValue();
14505 doForce : function(){
14506 if(this.inputEl().dom.value.length > 0){
14507 this.inputEl().dom.value =
14508 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14514 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14515 * query allowing the query action to be canceled if needed.
14516 * @param {String} query The SQL query to execute
14517 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14518 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14519 * saved in the current store (defaults to false)
14521 doQuery : function(q, forceAll){
14523 if(q === undefined || q === null){
14528 forceAll: forceAll,
14532 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14537 forceAll = qe.forceAll;
14538 if(forceAll === true || (q.length >= this.minChars)){
14540 this.hasQuery = true;
14542 if(this.lastQuery != q || this.alwaysQuery){
14543 this.lastQuery = q;
14544 if(this.mode == 'local'){
14545 this.selectedIndex = -1;
14547 this.store.clearFilter();
14550 if(this.specialFilter){
14551 this.fireEvent('specialfilter', this);
14556 this.store.filter(this.displayField, q);
14559 this.store.fireEvent("datachanged", this.store);
14566 this.store.baseParams[this.queryParam] = q;
14568 var options = {params : this.getParams(q)};
14571 options.add = true;
14572 options.params.start = this.page * this.pageSize;
14575 this.store.load(options);
14578 * this code will make the page width larger, at the beginning, the list not align correctly,
14579 * we should expand the list on onLoad
14580 * so command out it
14585 this.selectedIndex = -1;
14590 this.loadNext = false;
14594 getParams : function(q){
14596 //p[this.queryParam] = q;
14600 p.limit = this.pageSize;
14606 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14608 collapse : function(){
14609 if(!this.isExpanded()){
14615 this.hasFocus = false;
14619 this.cancelBtn.hide();
14620 this.trigger.show();
14623 this.tickableInputEl().dom.value = '';
14624 this.tickableInputEl().blur();
14629 Roo.get(document).un('mousedown', this.collapseIf, this);
14630 Roo.get(document).un('mousewheel', this.collapseIf, this);
14631 if (!this.editable) {
14632 Roo.get(document).un('keydown', this.listKeyPress, this);
14634 this.fireEvent('collapse', this);
14640 collapseIf : function(e){
14641 var in_combo = e.within(this.el);
14642 var in_list = e.within(this.list);
14643 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14645 if (in_combo || in_list || is_list) {
14646 //e.stopPropagation();
14651 this.onTickableFooterButtonClick(e, false, false);
14659 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14661 expand : function(){
14663 if(this.isExpanded() || !this.hasFocus){
14667 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14668 this.list.setWidth(lw);
14674 this.restrictHeight();
14678 this.tickItems = Roo.apply([], this.item);
14681 this.cancelBtn.show();
14682 this.trigger.hide();
14685 this.tickableInputEl().focus();
14690 Roo.get(document).on('mousedown', this.collapseIf, this);
14691 Roo.get(document).on('mousewheel', this.collapseIf, this);
14692 if (!this.editable) {
14693 Roo.get(document).on('keydown', this.listKeyPress, this);
14696 this.fireEvent('expand', this);
14700 // Implements the default empty TriggerField.onTriggerClick function
14701 onTriggerClick : function(e)
14703 Roo.log('trigger click');
14705 if(this.disabled || !this.triggerList){
14710 this.loadNext = false;
14712 if(this.isExpanded()){
14714 if (!this.blockFocus) {
14715 this.inputEl().focus();
14719 this.hasFocus = true;
14720 if(this.triggerAction == 'all') {
14721 this.doQuery(this.allQuery, true);
14723 this.doQuery(this.getRawValue());
14725 if (!this.blockFocus) {
14726 this.inputEl().focus();
14731 onTickableTriggerClick : function(e)
14738 this.loadNext = false;
14739 this.hasFocus = true;
14741 if(this.triggerAction == 'all') {
14742 this.doQuery(this.allQuery, true);
14744 this.doQuery(this.getRawValue());
14748 onSearchFieldClick : function(e)
14750 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14751 this.onTickableFooterButtonClick(e, false, false);
14755 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14760 this.loadNext = false;
14761 this.hasFocus = true;
14763 if(this.triggerAction == 'all') {
14764 this.doQuery(this.allQuery, true);
14766 this.doQuery(this.getRawValue());
14770 listKeyPress : function(e)
14772 //Roo.log('listkeypress');
14773 // scroll to first matching element based on key pres..
14774 if (e.isSpecialKey()) {
14777 var k = String.fromCharCode(e.getKey()).toUpperCase();
14780 var csel = this.view.getSelectedNodes();
14781 var cselitem = false;
14783 var ix = this.view.indexOf(csel[0]);
14784 cselitem = this.store.getAt(ix);
14785 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14791 this.store.each(function(v) {
14793 // start at existing selection.
14794 if (cselitem.id == v.id) {
14800 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14801 match = this.store.indexOf(v);
14807 if (match === false) {
14808 return true; // no more action?
14811 this.view.select(match);
14812 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14813 sn.scrollIntoView(sn.dom.parentNode, false);
14816 onViewScroll : function(e, t){
14818 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){
14822 this.hasQuery = true;
14824 this.loading = this.list.select('.loading', true).first();
14826 if(this.loading === null){
14827 this.list.createChild({
14829 cls: 'loading roo-select2-more-results roo-select2-active',
14830 html: 'Loading more results...'
14833 this.loading = this.list.select('.loading', true).first();
14835 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14837 this.loading.hide();
14840 this.loading.show();
14845 this.loadNext = true;
14847 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14852 addItem : function(o)
14854 var dv = ''; // display value
14856 if (this.displayField) {
14857 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14859 // this is an error condition!!!
14860 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14867 var choice = this.choices.createChild({
14869 cls: 'roo-select2-search-choice',
14878 cls: 'roo-select2-search-choice-close fa fa-times',
14883 }, this.searchField);
14885 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14887 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14895 this.inputEl().dom.value = '';
14900 onRemoveItem : function(e, _self, o)
14902 e.preventDefault();
14904 this.lastItem = Roo.apply([], this.item);
14906 var index = this.item.indexOf(o.data) * 1;
14909 Roo.log('not this item?!');
14913 this.item.splice(index, 1);
14918 this.fireEvent('remove', this, e);
14924 syncValue : function()
14926 if(!this.item.length){
14933 Roo.each(this.item, function(i){
14934 if(_this.valueField){
14935 value.push(i[_this.valueField]);
14942 this.value = value.join(',');
14944 if(this.hiddenField){
14945 this.hiddenField.dom.value = this.value;
14948 this.store.fireEvent("datachanged", this.store);
14953 clearItem : function()
14955 if(!this.multiple){
14961 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14969 if(this.tickable && !Roo.isTouch){
14970 this.view.refresh();
14974 inputEl: function ()
14976 if(Roo.isIOS && this.useNativeIOS){
14977 return this.el.select('select.roo-ios-select', true).first();
14980 if(Roo.isTouch && this.mobileTouchView){
14981 return this.el.select('input.form-control',true).first();
14985 return this.searchField;
14988 return this.el.select('input.form-control',true).first();
14991 onTickableFooterButtonClick : function(e, btn, el)
14993 e.preventDefault();
14995 this.lastItem = Roo.apply([], this.item);
14997 if(btn && btn.name == 'cancel'){
14998 this.tickItems = Roo.apply([], this.item);
15007 Roo.each(this.tickItems, function(o){
15015 validate : function()
15017 if(this.getVisibilityEl().hasClass('hidden')){
15021 var v = this.getRawValue();
15024 v = this.getValue();
15027 if(this.disabled || this.allowBlank || v.length){
15032 this.markInvalid();
15036 tickableInputEl : function()
15038 if(!this.tickable || !this.editable){
15039 return this.inputEl();
15042 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15046 getAutoCreateTouchView : function()
15051 cls: 'form-group' //input-group
15057 type : this.inputType,
15058 cls : 'form-control x-combo-noedit',
15059 autocomplete: 'new-password',
15060 placeholder : this.placeholder || '',
15065 input.name = this.name;
15069 input.cls += ' input-' + this.size;
15072 if (this.disabled) {
15073 input.disabled = true;
15084 inputblock.cls += ' input-group';
15086 inputblock.cn.unshift({
15088 cls : 'input-group-addon input-group-prepend input-group-text',
15093 if(this.removable && !this.multiple){
15094 inputblock.cls += ' roo-removable';
15096 inputblock.cn.push({
15099 cls : 'roo-combo-removable-btn close'
15103 if(this.hasFeedback && !this.allowBlank){
15105 inputblock.cls += ' has-feedback';
15107 inputblock.cn.push({
15109 cls: 'glyphicon form-control-feedback'
15116 inputblock.cls += (this.before) ? '' : ' input-group';
15118 inputblock.cn.push({
15120 cls : 'input-group-addon input-group-append input-group-text',
15131 cls: 'form-hidden-field'
15145 cls: 'form-hidden-field'
15149 cls: 'roo-select2-choices',
15153 cls: 'roo-select2-search-field',
15166 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15172 if(!this.multiple && this.showToggleBtn){
15179 if (this.caret != false) {
15182 cls: 'fa fa-' + this.caret
15189 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15194 cls: 'combobox-clear',
15208 combobox.cls += ' roo-select2-container-multi';
15211 var align = this.labelAlign || this.parentLabelAlign();
15213 if (align ==='left' && this.fieldLabel.length) {
15218 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15219 tooltip : 'This field is required'
15223 cls : 'control-label col-form-label',
15224 html : this.fieldLabel
15235 var labelCfg = cfg.cn[1];
15236 var contentCfg = cfg.cn[2];
15239 if(this.indicatorpos == 'right'){
15244 cls : 'control-label col-form-label',
15248 html : this.fieldLabel
15252 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15253 tooltip : 'This field is required'
15266 labelCfg = cfg.cn[0];
15267 contentCfg = cfg.cn[1];
15272 if(this.labelWidth > 12){
15273 labelCfg.style = "width: " + this.labelWidth + 'px';
15276 if(this.labelWidth < 13 && this.labelmd == 0){
15277 this.labelmd = this.labelWidth;
15280 if(this.labellg > 0){
15281 labelCfg.cls += ' col-lg-' + this.labellg;
15282 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15285 if(this.labelmd > 0){
15286 labelCfg.cls += ' col-md-' + this.labelmd;
15287 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15290 if(this.labelsm > 0){
15291 labelCfg.cls += ' col-sm-' + this.labelsm;
15292 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15295 if(this.labelxs > 0){
15296 labelCfg.cls += ' col-xs-' + this.labelxs;
15297 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15301 } else if ( this.fieldLabel.length) {
15305 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15306 tooltip : 'This field is required'
15310 cls : 'control-label',
15311 html : this.fieldLabel
15322 if(this.indicatorpos == 'right'){
15326 cls : 'control-label',
15327 html : this.fieldLabel,
15331 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15332 tooltip : 'This field is required'
15349 var settings = this;
15351 ['xs','sm','md','lg'].map(function(size){
15352 if (settings[size]) {
15353 cfg.cls += ' col-' + size + '-' + settings[size];
15360 initTouchView : function()
15362 this.renderTouchView();
15364 this.touchViewEl.on('scroll', function(){
15365 this.el.dom.scrollTop = 0;
15368 this.originalValue = this.getValue();
15370 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15372 this.inputEl().on("click", this.showTouchView, this);
15373 if (this.triggerEl) {
15374 this.triggerEl.on("click", this.showTouchView, this);
15378 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15379 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15381 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15383 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15384 this.store.on('load', this.onTouchViewLoad, this);
15385 this.store.on('loadexception', this.onTouchViewLoadException, this);
15387 if(this.hiddenName){
15389 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15391 this.hiddenField.dom.value =
15392 this.hiddenValue !== undefined ? this.hiddenValue :
15393 this.value !== undefined ? this.value : '';
15395 this.el.dom.removeAttribute('name');
15396 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15400 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15401 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15404 if(this.removable && !this.multiple){
15405 var close = this.closeTriggerEl();
15407 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15408 close.on('click', this.removeBtnClick, this, close);
15412 * fix the bug in Safari iOS8
15414 this.inputEl().on("focus", function(e){
15415 document.activeElement.blur();
15418 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15425 renderTouchView : function()
15427 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15428 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15430 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15431 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15433 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15434 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15435 this.touchViewBodyEl.setStyle('overflow', 'auto');
15437 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15438 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15440 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15441 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15445 showTouchView : function()
15451 this.touchViewHeaderEl.hide();
15453 if(this.modalTitle.length){
15454 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15455 this.touchViewHeaderEl.show();
15458 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15459 this.touchViewEl.show();
15461 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15463 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15464 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15466 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15468 if(this.modalTitle.length){
15469 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15472 this.touchViewBodyEl.setHeight(bodyHeight);
15476 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15478 this.touchViewEl.addClass('in');
15481 if(this._touchViewMask){
15482 Roo.get(document.body).addClass("x-body-masked");
15483 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15484 this._touchViewMask.setStyle('z-index', 10000);
15485 this._touchViewMask.addClass('show');
15488 this.doTouchViewQuery();
15492 hideTouchView : function()
15494 this.touchViewEl.removeClass('in');
15498 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15500 this.touchViewEl.setStyle('display', 'none');
15503 if(this._touchViewMask){
15504 this._touchViewMask.removeClass('show');
15505 Roo.get(document.body).removeClass("x-body-masked");
15509 setTouchViewValue : function()
15516 Roo.each(this.tickItems, function(o){
15521 this.hideTouchView();
15524 doTouchViewQuery : function()
15533 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15537 if(!this.alwaysQuery || this.mode == 'local'){
15538 this.onTouchViewLoad();
15545 onTouchViewBeforeLoad : function(combo,opts)
15551 onTouchViewLoad : function()
15553 if(this.store.getCount() < 1){
15554 this.onTouchViewEmptyResults();
15558 this.clearTouchView();
15560 var rawValue = this.getRawValue();
15562 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15564 this.tickItems = [];
15566 this.store.data.each(function(d, rowIndex){
15567 var row = this.touchViewListGroup.createChild(template);
15569 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15570 row.addClass(d.data.cls);
15573 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15576 html : d.data[this.displayField]
15579 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15580 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15583 row.removeClass('selected');
15584 if(!this.multiple && this.valueField &&
15585 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15588 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15589 row.addClass('selected');
15592 if(this.multiple && this.valueField &&
15593 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15597 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15598 this.tickItems.push(d.data);
15601 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15605 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15607 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15609 if(this.modalTitle.length){
15610 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15613 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15615 if(this.mobile_restrict_height && listHeight < bodyHeight){
15616 this.touchViewBodyEl.setHeight(listHeight);
15621 if(firstChecked && listHeight > bodyHeight){
15622 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15627 onTouchViewLoadException : function()
15629 this.hideTouchView();
15632 onTouchViewEmptyResults : function()
15634 this.clearTouchView();
15636 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15638 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15642 clearTouchView : function()
15644 this.touchViewListGroup.dom.innerHTML = '';
15647 onTouchViewClick : function(e, el, o)
15649 e.preventDefault();
15652 var rowIndex = o.rowIndex;
15654 var r = this.store.getAt(rowIndex);
15656 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15658 if(!this.multiple){
15659 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15660 c.dom.removeAttribute('checked');
15663 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15665 this.setFromData(r.data);
15667 var close = this.closeTriggerEl();
15673 this.hideTouchView();
15675 this.fireEvent('select', this, r, rowIndex);
15680 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15681 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15682 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15686 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15687 this.addItem(r.data);
15688 this.tickItems.push(r.data);
15692 getAutoCreateNativeIOS : function()
15695 cls: 'form-group' //input-group,
15700 cls : 'roo-ios-select'
15704 combobox.name = this.name;
15707 if (this.disabled) {
15708 combobox.disabled = true;
15711 var settings = this;
15713 ['xs','sm','md','lg'].map(function(size){
15714 if (settings[size]) {
15715 cfg.cls += ' col-' + size + '-' + settings[size];
15725 initIOSView : function()
15727 this.store.on('load', this.onIOSViewLoad, this);
15732 onIOSViewLoad : function()
15734 if(this.store.getCount() < 1){
15738 this.clearIOSView();
15740 if(this.allowBlank) {
15742 var default_text = '-- SELECT --';
15744 if(this.placeholder.length){
15745 default_text = this.placeholder;
15748 if(this.emptyTitle.length){
15749 default_text += ' - ' + this.emptyTitle + ' -';
15752 var opt = this.inputEl().createChild({
15755 html : default_text
15759 o[this.valueField] = 0;
15760 o[this.displayField] = default_text;
15762 this.ios_options.push({
15769 this.store.data.each(function(d, rowIndex){
15773 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15774 html = d.data[this.displayField];
15779 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15780 value = d.data[this.valueField];
15789 if(this.value == d.data[this.valueField]){
15790 option['selected'] = true;
15793 var opt = this.inputEl().createChild(option);
15795 this.ios_options.push({
15802 this.inputEl().on('change', function(){
15803 this.fireEvent('select', this);
15808 clearIOSView: function()
15810 this.inputEl().dom.innerHTML = '';
15812 this.ios_options = [];
15815 setIOSValue: function(v)
15819 if(!this.ios_options){
15823 Roo.each(this.ios_options, function(opts){
15825 opts.el.dom.removeAttribute('selected');
15827 if(opts.data[this.valueField] != v){
15831 opts.el.dom.setAttribute('selected', true);
15837 * @cfg {Boolean} grow
15841 * @cfg {Number} growMin
15845 * @cfg {Number} growMax
15854 Roo.apply(Roo.bootstrap.ComboBox, {
15858 cls: 'modal-header',
15880 cls: 'list-group-item',
15884 cls: 'roo-combobox-list-group-item-value'
15888 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15902 listItemCheckbox : {
15904 cls: 'list-group-item',
15908 cls: 'roo-combobox-list-group-item-value'
15912 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15928 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15933 cls: 'modal-footer',
15941 cls: 'col-xs-6 text-left',
15944 cls: 'btn btn-danger roo-touch-view-cancel',
15950 cls: 'col-xs-6 text-right',
15953 cls: 'btn btn-success roo-touch-view-ok',
15964 Roo.apply(Roo.bootstrap.ComboBox, {
15966 touchViewTemplate : {
15968 cls: 'modal fade roo-combobox-touch-view',
15972 cls: 'modal-dialog',
15973 style : 'position:fixed', // we have to fix position....
15977 cls: 'modal-content',
15979 Roo.bootstrap.ComboBox.header,
15980 Roo.bootstrap.ComboBox.body,
15981 Roo.bootstrap.ComboBox.footer
15990 * Ext JS Library 1.1.1
15991 * Copyright(c) 2006-2007, Ext JS, LLC.
15993 * Originally Released Under LGPL - original licence link has changed is not relivant.
15996 * <script type="text/javascript">
16001 * @extends Roo.util.Observable
16002 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16003 * This class also supports single and multi selection modes. <br>
16004 * Create a data model bound view:
16006 var store = new Roo.data.Store(...);
16008 var view = new Roo.View({
16010 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16012 singleSelect: true,
16013 selectedClass: "ydataview-selected",
16017 // listen for node click?
16018 view.on("click", function(vw, index, node, e){
16019 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16023 dataModel.load("foobar.xml");
16025 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16027 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16028 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16030 * Note: old style constructor is still suported (container, template, config)
16033 * Create a new View
16034 * @param {Object} config The config object
16037 Roo.View = function(config, depreciated_tpl, depreciated_config){
16039 this.parent = false;
16041 if (typeof(depreciated_tpl) == 'undefined') {
16042 // new way.. - universal constructor.
16043 Roo.apply(this, config);
16044 this.el = Roo.get(this.el);
16047 this.el = Roo.get(config);
16048 this.tpl = depreciated_tpl;
16049 Roo.apply(this, depreciated_config);
16051 this.wrapEl = this.el.wrap().wrap();
16052 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16055 if(typeof(this.tpl) == "string"){
16056 this.tpl = new Roo.Template(this.tpl);
16058 // support xtype ctors..
16059 this.tpl = new Roo.factory(this.tpl, Roo);
16063 this.tpl.compile();
16068 * @event beforeclick
16069 * Fires before a click is processed. Returns false to cancel the default action.
16070 * @param {Roo.View} this
16071 * @param {Number} index The index of the target node
16072 * @param {HTMLElement} node The target node
16073 * @param {Roo.EventObject} e The raw event object
16075 "beforeclick" : true,
16078 * Fires when a template node is clicked.
16079 * @param {Roo.View} this
16080 * @param {Number} index The index of the target node
16081 * @param {HTMLElement} node The target node
16082 * @param {Roo.EventObject} e The raw event object
16087 * Fires when a template node is double clicked.
16088 * @param {Roo.View} this
16089 * @param {Number} index The index of the target node
16090 * @param {HTMLElement} node The target node
16091 * @param {Roo.EventObject} e The raw event object
16095 * @event contextmenu
16096 * Fires when a template node is right clicked.
16097 * @param {Roo.View} this
16098 * @param {Number} index The index of the target node
16099 * @param {HTMLElement} node The target node
16100 * @param {Roo.EventObject} e The raw event object
16102 "contextmenu" : true,
16104 * @event selectionchange
16105 * Fires when the selected nodes change.
16106 * @param {Roo.View} this
16107 * @param {Array} selections Array of the selected nodes
16109 "selectionchange" : true,
16112 * @event beforeselect
16113 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16114 * @param {Roo.View} this
16115 * @param {HTMLElement} node The node to be selected
16116 * @param {Array} selections Array of currently selected nodes
16118 "beforeselect" : true,
16120 * @event preparedata
16121 * Fires on every row to render, to allow you to change the data.
16122 * @param {Roo.View} this
16123 * @param {Object} data to be rendered (change this)
16125 "preparedata" : true
16133 "click": this.onClick,
16134 "dblclick": this.onDblClick,
16135 "contextmenu": this.onContextMenu,
16139 this.selections = [];
16141 this.cmp = new Roo.CompositeElementLite([]);
16143 this.store = Roo.factory(this.store, Roo.data);
16144 this.setStore(this.store, true);
16147 if ( this.footer && this.footer.xtype) {
16149 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16151 this.footer.dataSource = this.store;
16152 this.footer.container = fctr;
16153 this.footer = Roo.factory(this.footer, Roo);
16154 fctr.insertFirst(this.el);
16156 // this is a bit insane - as the paging toolbar seems to detach the el..
16157 // dom.parentNode.parentNode.parentNode
16158 // they get detached?
16162 Roo.View.superclass.constructor.call(this);
16167 Roo.extend(Roo.View, Roo.util.Observable, {
16170 * @cfg {Roo.data.Store} store Data store to load data from.
16175 * @cfg {String|Roo.Element} el The container element.
16180 * @cfg {String|Roo.Template} tpl The template used by this View
16184 * @cfg {String} dataName the named area of the template to use as the data area
16185 * Works with domtemplates roo-name="name"
16189 * @cfg {String} selectedClass The css class to add to selected nodes
16191 selectedClass : "x-view-selected",
16193 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16198 * @cfg {String} text to display on mask (default Loading)
16202 * @cfg {Boolean} multiSelect Allow multiple selection
16204 multiSelect : false,
16206 * @cfg {Boolean} singleSelect Allow single selection
16208 singleSelect: false,
16211 * @cfg {Boolean} toggleSelect - selecting
16213 toggleSelect : false,
16216 * @cfg {Boolean} tickable - selecting
16221 * Returns the element this view is bound to.
16222 * @return {Roo.Element}
16224 getEl : function(){
16225 return this.wrapEl;
16231 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16233 refresh : function(){
16234 //Roo.log('refresh');
16237 // if we are using something like 'domtemplate', then
16238 // the what gets used is:
16239 // t.applySubtemplate(NAME, data, wrapping data..)
16240 // the outer template then get' applied with
16241 // the store 'extra data'
16242 // and the body get's added to the
16243 // roo-name="data" node?
16244 // <span class='roo-tpl-{name}'></span> ?????
16248 this.clearSelections();
16249 this.el.update("");
16251 var records = this.store.getRange();
16252 if(records.length < 1) {
16254 // is this valid?? = should it render a template??
16256 this.el.update(this.emptyText);
16260 if (this.dataName) {
16261 this.el.update(t.apply(this.store.meta)); //????
16262 el = this.el.child('.roo-tpl-' + this.dataName);
16265 for(var i = 0, len = records.length; i < len; i++){
16266 var data = this.prepareData(records[i].data, i, records[i]);
16267 this.fireEvent("preparedata", this, data, i, records[i]);
16269 var d = Roo.apply({}, data);
16272 Roo.apply(d, {'roo-id' : Roo.id()});
16276 Roo.each(this.parent.item, function(item){
16277 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16280 Roo.apply(d, {'roo-data-checked' : 'checked'});
16284 html[html.length] = Roo.util.Format.trim(
16286 t.applySubtemplate(this.dataName, d, this.store.meta) :
16293 el.update(html.join(""));
16294 this.nodes = el.dom.childNodes;
16295 this.updateIndexes(0);
16300 * Function to override to reformat the data that is sent to
16301 * the template for each node.
16302 * DEPRICATED - use the preparedata event handler.
16303 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16304 * a JSON object for an UpdateManager bound view).
16306 prepareData : function(data, index, record)
16308 this.fireEvent("preparedata", this, data, index, record);
16312 onUpdate : function(ds, record){
16313 // Roo.log('on update');
16314 this.clearSelections();
16315 var index = this.store.indexOf(record);
16316 var n = this.nodes[index];
16317 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16318 n.parentNode.removeChild(n);
16319 this.updateIndexes(index, index);
16325 onAdd : function(ds, records, index)
16327 //Roo.log(['on Add', ds, records, index] );
16328 this.clearSelections();
16329 if(this.nodes.length == 0){
16333 var n = this.nodes[index];
16334 for(var i = 0, len = records.length; i < len; i++){
16335 var d = this.prepareData(records[i].data, i, records[i]);
16337 this.tpl.insertBefore(n, d);
16340 this.tpl.append(this.el, d);
16343 this.updateIndexes(index);
16346 onRemove : function(ds, record, index){
16347 // Roo.log('onRemove');
16348 this.clearSelections();
16349 var el = this.dataName ?
16350 this.el.child('.roo-tpl-' + this.dataName) :
16353 el.dom.removeChild(this.nodes[index]);
16354 this.updateIndexes(index);
16358 * Refresh an individual node.
16359 * @param {Number} index
16361 refreshNode : function(index){
16362 this.onUpdate(this.store, this.store.getAt(index));
16365 updateIndexes : function(startIndex, endIndex){
16366 var ns = this.nodes;
16367 startIndex = startIndex || 0;
16368 endIndex = endIndex || ns.length - 1;
16369 for(var i = startIndex; i <= endIndex; i++){
16370 ns[i].nodeIndex = i;
16375 * Changes the data store this view uses and refresh the view.
16376 * @param {Store} store
16378 setStore : function(store, initial){
16379 if(!initial && this.store){
16380 this.store.un("datachanged", this.refresh);
16381 this.store.un("add", this.onAdd);
16382 this.store.un("remove", this.onRemove);
16383 this.store.un("update", this.onUpdate);
16384 this.store.un("clear", this.refresh);
16385 this.store.un("beforeload", this.onBeforeLoad);
16386 this.store.un("load", this.onLoad);
16387 this.store.un("loadexception", this.onLoad);
16391 store.on("datachanged", this.refresh, this);
16392 store.on("add", this.onAdd, this);
16393 store.on("remove", this.onRemove, this);
16394 store.on("update", this.onUpdate, this);
16395 store.on("clear", this.refresh, this);
16396 store.on("beforeload", this.onBeforeLoad, this);
16397 store.on("load", this.onLoad, this);
16398 store.on("loadexception", this.onLoad, this);
16406 * onbeforeLoad - masks the loading area.
16409 onBeforeLoad : function(store,opts)
16411 //Roo.log('onBeforeLoad');
16413 this.el.update("");
16415 this.el.mask(this.mask ? this.mask : "Loading" );
16417 onLoad : function ()
16424 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16425 * @param {HTMLElement} node
16426 * @return {HTMLElement} The template node
16428 findItemFromChild : function(node){
16429 var el = this.dataName ?
16430 this.el.child('.roo-tpl-' + this.dataName,true) :
16433 if(!node || node.parentNode == el){
16436 var p = node.parentNode;
16437 while(p && p != el){
16438 if(p.parentNode == el){
16447 onClick : function(e){
16448 var item = this.findItemFromChild(e.getTarget());
16450 var index = this.indexOf(item);
16451 if(this.onItemClick(item, index, e) !== false){
16452 this.fireEvent("click", this, index, item, e);
16455 this.clearSelections();
16460 onContextMenu : function(e){
16461 var item = this.findItemFromChild(e.getTarget());
16463 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16468 onDblClick : function(e){
16469 var item = this.findItemFromChild(e.getTarget());
16471 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16475 onItemClick : function(item, index, e)
16477 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16480 if (this.toggleSelect) {
16481 var m = this.isSelected(item) ? 'unselect' : 'select';
16484 _t[m](item, true, false);
16487 if(this.multiSelect || this.singleSelect){
16488 if(this.multiSelect && e.shiftKey && this.lastSelection){
16489 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16491 this.select(item, this.multiSelect && e.ctrlKey);
16492 this.lastSelection = item;
16495 if(!this.tickable){
16496 e.preventDefault();
16504 * Get the number of selected nodes.
16507 getSelectionCount : function(){
16508 return this.selections.length;
16512 * Get the currently selected nodes.
16513 * @return {Array} An array of HTMLElements
16515 getSelectedNodes : function(){
16516 return this.selections;
16520 * Get the indexes of the selected nodes.
16523 getSelectedIndexes : function(){
16524 var indexes = [], s = this.selections;
16525 for(var i = 0, len = s.length; i < len; i++){
16526 indexes.push(s[i].nodeIndex);
16532 * Clear all selections
16533 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16535 clearSelections : function(suppressEvent){
16536 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16537 this.cmp.elements = this.selections;
16538 this.cmp.removeClass(this.selectedClass);
16539 this.selections = [];
16540 if(!suppressEvent){
16541 this.fireEvent("selectionchange", this, this.selections);
16547 * Returns true if the passed node is selected
16548 * @param {HTMLElement/Number} node The node or node index
16549 * @return {Boolean}
16551 isSelected : function(node){
16552 var s = this.selections;
16556 node = this.getNode(node);
16557 return s.indexOf(node) !== -1;
16562 * @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
16563 * @param {Boolean} keepExisting (optional) true to keep existing selections
16564 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16566 select : function(nodeInfo, keepExisting, suppressEvent){
16567 if(nodeInfo instanceof Array){
16569 this.clearSelections(true);
16571 for(var i = 0, len = nodeInfo.length; i < len; i++){
16572 this.select(nodeInfo[i], true, true);
16576 var node = this.getNode(nodeInfo);
16577 if(!node || this.isSelected(node)){
16578 return; // already selected.
16581 this.clearSelections(true);
16584 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16585 Roo.fly(node).addClass(this.selectedClass);
16586 this.selections.push(node);
16587 if(!suppressEvent){
16588 this.fireEvent("selectionchange", this, this.selections);
16596 * @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
16597 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16598 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16600 unselect : function(nodeInfo, keepExisting, suppressEvent)
16602 if(nodeInfo instanceof Array){
16603 Roo.each(this.selections, function(s) {
16604 this.unselect(s, nodeInfo);
16608 var node = this.getNode(nodeInfo);
16609 if(!node || !this.isSelected(node)){
16610 //Roo.log("not selected");
16611 return; // not selected.
16615 Roo.each(this.selections, function(s) {
16617 Roo.fly(node).removeClass(this.selectedClass);
16624 this.selections= ns;
16625 this.fireEvent("selectionchange", this, this.selections);
16629 * Gets a template node.
16630 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16631 * @return {HTMLElement} The node or null if it wasn't found
16633 getNode : function(nodeInfo){
16634 if(typeof nodeInfo == "string"){
16635 return document.getElementById(nodeInfo);
16636 }else if(typeof nodeInfo == "number"){
16637 return this.nodes[nodeInfo];
16643 * Gets a range template nodes.
16644 * @param {Number} startIndex
16645 * @param {Number} endIndex
16646 * @return {Array} An array of nodes
16648 getNodes : function(start, end){
16649 var ns = this.nodes;
16650 start = start || 0;
16651 end = typeof end == "undefined" ? ns.length - 1 : end;
16654 for(var i = start; i <= end; i++){
16658 for(var i = start; i >= end; i--){
16666 * Finds the index of the passed node
16667 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16668 * @return {Number} The index of the node or -1
16670 indexOf : function(node){
16671 node = this.getNode(node);
16672 if(typeof node.nodeIndex == "number"){
16673 return node.nodeIndex;
16675 var ns = this.nodes;
16676 for(var i = 0, len = ns.length; i < len; i++){
16687 * based on jquery fullcalendar
16691 Roo.bootstrap = Roo.bootstrap || {};
16693 * @class Roo.bootstrap.Calendar
16694 * @extends Roo.bootstrap.Component
16695 * Bootstrap Calendar class
16696 * @cfg {Boolean} loadMask (true|false) default false
16697 * @cfg {Object} header generate the user specific header of the calendar, default false
16700 * Create a new Container
16701 * @param {Object} config The config object
16706 Roo.bootstrap.Calendar = function(config){
16707 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16711 * Fires when a date is selected
16712 * @param {DatePicker} this
16713 * @param {Date} date The selected date
16717 * @event monthchange
16718 * Fires when the displayed month changes
16719 * @param {DatePicker} this
16720 * @param {Date} date The selected month
16722 'monthchange': true,
16724 * @event evententer
16725 * Fires when mouse over an event
16726 * @param {Calendar} this
16727 * @param {event} Event
16729 'evententer': true,
16731 * @event eventleave
16732 * Fires when the mouse leaves an
16733 * @param {Calendar} this
16736 'eventleave': true,
16738 * @event eventclick
16739 * Fires when the mouse click an
16740 * @param {Calendar} this
16749 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16752 * @cfg {Number} startDay
16753 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16761 getAutoCreate : function(){
16764 var fc_button = function(name, corner, style, content ) {
16765 return Roo.apply({},{
16767 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16769 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16772 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16783 style : 'width:100%',
16790 cls : 'fc-header-left',
16792 fc_button('prev', 'left', 'arrow', '‹' ),
16793 fc_button('next', 'right', 'arrow', '›' ),
16794 { tag: 'span', cls: 'fc-header-space' },
16795 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16803 cls : 'fc-header-center',
16807 cls: 'fc-header-title',
16810 html : 'month / year'
16818 cls : 'fc-header-right',
16820 /* fc_button('month', 'left', '', 'month' ),
16821 fc_button('week', '', '', 'week' ),
16822 fc_button('day', 'right', '', 'day' )
16834 header = this.header;
16837 var cal_heads = function() {
16839 // fixme - handle this.
16841 for (var i =0; i < Date.dayNames.length; i++) {
16842 var d = Date.dayNames[i];
16845 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16846 html : d.substring(0,3)
16850 ret[0].cls += ' fc-first';
16851 ret[6].cls += ' fc-last';
16854 var cal_cell = function(n) {
16857 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16862 cls: 'fc-day-number',
16866 cls: 'fc-day-content',
16870 style: 'position: relative;' // height: 17px;
16882 var cal_rows = function() {
16885 for (var r = 0; r < 6; r++) {
16892 for (var i =0; i < Date.dayNames.length; i++) {
16893 var d = Date.dayNames[i];
16894 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16897 row.cn[0].cls+=' fc-first';
16898 row.cn[0].cn[0].style = 'min-height:90px';
16899 row.cn[6].cls+=' fc-last';
16903 ret[0].cls += ' fc-first';
16904 ret[4].cls += ' fc-prev-last';
16905 ret[5].cls += ' fc-last';
16912 cls: 'fc-border-separate',
16913 style : 'width:100%',
16921 cls : 'fc-first fc-last',
16939 cls : 'fc-content',
16940 style : "position: relative;",
16943 cls : 'fc-view fc-view-month fc-grid',
16944 style : 'position: relative',
16945 unselectable : 'on',
16948 cls : 'fc-event-container',
16949 style : 'position:absolute;z-index:8;top:0;left:0;'
16967 initEvents : function()
16970 throw "can not find store for calendar";
16976 style: "text-align:center",
16980 style: "background-color:white;width:50%;margin:250 auto",
16984 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16995 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16997 var size = this.el.select('.fc-content', true).first().getSize();
16998 this.maskEl.setSize(size.width, size.height);
16999 this.maskEl.enableDisplayMode("block");
17000 if(!this.loadMask){
17001 this.maskEl.hide();
17004 this.store = Roo.factory(this.store, Roo.data);
17005 this.store.on('load', this.onLoad, this);
17006 this.store.on('beforeload', this.onBeforeLoad, this);
17010 this.cells = this.el.select('.fc-day',true);
17011 //Roo.log(this.cells);
17012 this.textNodes = this.el.query('.fc-day-number');
17013 this.cells.addClassOnOver('fc-state-hover');
17015 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17016 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17017 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17018 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17020 this.on('monthchange', this.onMonthChange, this);
17022 this.update(new Date().clearTime());
17025 resize : function() {
17026 var sz = this.el.getSize();
17028 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17029 this.el.select('.fc-day-content div',true).setHeight(34);
17034 showPrevMonth : function(e){
17035 this.update(this.activeDate.add("mo", -1));
17037 showToday : function(e){
17038 this.update(new Date().clearTime());
17041 showNextMonth : function(e){
17042 this.update(this.activeDate.add("mo", 1));
17046 showPrevYear : function(){
17047 this.update(this.activeDate.add("y", -1));
17051 showNextYear : function(){
17052 this.update(this.activeDate.add("y", 1));
17057 update : function(date)
17059 var vd = this.activeDate;
17060 this.activeDate = date;
17061 // if(vd && this.el){
17062 // var t = date.getTime();
17063 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17064 // Roo.log('using add remove');
17066 // this.fireEvent('monthchange', this, date);
17068 // this.cells.removeClass("fc-state-highlight");
17069 // this.cells.each(function(c){
17070 // if(c.dateValue == t){
17071 // c.addClass("fc-state-highlight");
17072 // setTimeout(function(){
17073 // try{c.dom.firstChild.focus();}catch(e){}
17083 var days = date.getDaysInMonth();
17085 var firstOfMonth = date.getFirstDateOfMonth();
17086 var startingPos = firstOfMonth.getDay()-this.startDay;
17088 if(startingPos < this.startDay){
17092 var pm = date.add(Date.MONTH, -1);
17093 var prevStart = pm.getDaysInMonth()-startingPos;
17095 this.cells = this.el.select('.fc-day',true);
17096 this.textNodes = this.el.query('.fc-day-number');
17097 this.cells.addClassOnOver('fc-state-hover');
17099 var cells = this.cells.elements;
17100 var textEls = this.textNodes;
17102 Roo.each(cells, function(cell){
17103 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17106 days += startingPos;
17108 // convert everything to numbers so it's fast
17109 var day = 86400000;
17110 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17113 //Roo.log(prevStart);
17115 var today = new Date().clearTime().getTime();
17116 var sel = date.clearTime().getTime();
17117 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17118 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17119 var ddMatch = this.disabledDatesRE;
17120 var ddText = this.disabledDatesText;
17121 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17122 var ddaysText = this.disabledDaysText;
17123 var format = this.format;
17125 var setCellClass = function(cal, cell){
17129 //Roo.log('set Cell Class');
17131 var t = d.getTime();
17135 cell.dateValue = t;
17137 cell.className += " fc-today";
17138 cell.className += " fc-state-highlight";
17139 cell.title = cal.todayText;
17142 // disable highlight in other month..
17143 //cell.className += " fc-state-highlight";
17148 cell.className = " fc-state-disabled";
17149 cell.title = cal.minText;
17153 cell.className = " fc-state-disabled";
17154 cell.title = cal.maxText;
17158 if(ddays.indexOf(d.getDay()) != -1){
17159 cell.title = ddaysText;
17160 cell.className = " fc-state-disabled";
17163 if(ddMatch && format){
17164 var fvalue = d.dateFormat(format);
17165 if(ddMatch.test(fvalue)){
17166 cell.title = ddText.replace("%0", fvalue);
17167 cell.className = " fc-state-disabled";
17171 if (!cell.initialClassName) {
17172 cell.initialClassName = cell.dom.className;
17175 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17180 for(; i < startingPos; i++) {
17181 textEls[i].innerHTML = (++prevStart);
17182 d.setDate(d.getDate()+1);
17184 cells[i].className = "fc-past fc-other-month";
17185 setCellClass(this, cells[i]);
17190 for(; i < days; i++){
17191 intDay = i - startingPos + 1;
17192 textEls[i].innerHTML = (intDay);
17193 d.setDate(d.getDate()+1);
17195 cells[i].className = ''; // "x-date-active";
17196 setCellClass(this, cells[i]);
17200 for(; i < 42; i++) {
17201 textEls[i].innerHTML = (++extraDays);
17202 d.setDate(d.getDate()+1);
17204 cells[i].className = "fc-future fc-other-month";
17205 setCellClass(this, cells[i]);
17208 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17210 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17212 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17213 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17215 if(totalRows != 6){
17216 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17217 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17220 this.fireEvent('monthchange', this, date);
17224 if(!this.internalRender){
17225 var main = this.el.dom.firstChild;
17226 var w = main.offsetWidth;
17227 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17228 Roo.fly(main).setWidth(w);
17229 this.internalRender = true;
17230 // opera does not respect the auto grow header center column
17231 // then, after it gets a width opera refuses to recalculate
17232 // without a second pass
17233 if(Roo.isOpera && !this.secondPass){
17234 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17235 this.secondPass = true;
17236 this.update.defer(10, this, [date]);
17243 findCell : function(dt) {
17244 dt = dt.clearTime().getTime();
17246 this.cells.each(function(c){
17247 //Roo.log("check " +c.dateValue + '?=' + dt);
17248 if(c.dateValue == dt){
17258 findCells : function(ev) {
17259 var s = ev.start.clone().clearTime().getTime();
17261 var e= ev.end.clone().clearTime().getTime();
17264 this.cells.each(function(c){
17265 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17267 if(c.dateValue > e){
17270 if(c.dateValue < s){
17279 // findBestRow: function(cells)
17283 // for (var i =0 ; i < cells.length;i++) {
17284 // ret = Math.max(cells[i].rows || 0,ret);
17291 addItem : function(ev)
17293 // look for vertical location slot in
17294 var cells = this.findCells(ev);
17296 // ev.row = this.findBestRow(cells);
17298 // work out the location.
17302 for(var i =0; i < cells.length; i++) {
17304 cells[i].row = cells[0].row;
17307 cells[i].row = cells[i].row + 1;
17317 if (crow.start.getY() == cells[i].getY()) {
17319 crow.end = cells[i];
17336 cells[0].events.push(ev);
17338 this.calevents.push(ev);
17341 clearEvents: function() {
17343 if(!this.calevents){
17347 Roo.each(this.cells.elements, function(c){
17353 Roo.each(this.calevents, function(e) {
17354 Roo.each(e.els, function(el) {
17355 el.un('mouseenter' ,this.onEventEnter, this);
17356 el.un('mouseleave' ,this.onEventLeave, this);
17361 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17367 renderEvents: function()
17371 this.cells.each(function(c) {
17380 if(c.row != c.events.length){
17381 r = 4 - (4 - (c.row - c.events.length));
17384 c.events = ev.slice(0, r);
17385 c.more = ev.slice(r);
17387 if(c.more.length && c.more.length == 1){
17388 c.events.push(c.more.pop());
17391 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17395 this.cells.each(function(c) {
17397 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17400 for (var e = 0; e < c.events.length; e++){
17401 var ev = c.events[e];
17402 var rows = ev.rows;
17404 for(var i = 0; i < rows.length; i++) {
17406 // how many rows should it span..
17409 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17410 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17412 unselectable : "on",
17415 cls: 'fc-event-inner',
17419 // cls: 'fc-event-time',
17420 // html : cells.length > 1 ? '' : ev.time
17424 cls: 'fc-event-title',
17425 html : String.format('{0}', ev.title)
17432 cls: 'ui-resizable-handle ui-resizable-e',
17433 html : '  '
17440 cfg.cls += ' fc-event-start';
17442 if ((i+1) == rows.length) {
17443 cfg.cls += ' fc-event-end';
17446 var ctr = _this.el.select('.fc-event-container',true).first();
17447 var cg = ctr.createChild(cfg);
17449 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17450 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17452 var r = (c.more.length) ? 1 : 0;
17453 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17454 cg.setWidth(ebox.right - sbox.x -2);
17456 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17457 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17458 cg.on('click', _this.onEventClick, _this, ev);
17469 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17470 style : 'position: absolute',
17471 unselectable : "on",
17474 cls: 'fc-event-inner',
17478 cls: 'fc-event-title',
17486 cls: 'ui-resizable-handle ui-resizable-e',
17487 html : '  '
17493 var ctr = _this.el.select('.fc-event-container',true).first();
17494 var cg = ctr.createChild(cfg);
17496 var sbox = c.select('.fc-day-content',true).first().getBox();
17497 var ebox = c.select('.fc-day-content',true).first().getBox();
17499 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17500 cg.setWidth(ebox.right - sbox.x -2);
17502 cg.on('click', _this.onMoreEventClick, _this, c.more);
17512 onEventEnter: function (e, el,event,d) {
17513 this.fireEvent('evententer', this, el, event);
17516 onEventLeave: function (e, el,event,d) {
17517 this.fireEvent('eventleave', this, el, event);
17520 onEventClick: function (e, el,event,d) {
17521 this.fireEvent('eventclick', this, el, event);
17524 onMonthChange: function () {
17528 onMoreEventClick: function(e, el, more)
17532 this.calpopover.placement = 'right';
17533 this.calpopover.setTitle('More');
17535 this.calpopover.setContent('');
17537 var ctr = this.calpopover.el.select('.popover-content', true).first();
17539 Roo.each(more, function(m){
17541 cls : 'fc-event-hori fc-event-draggable',
17544 var cg = ctr.createChild(cfg);
17546 cg.on('click', _this.onEventClick, _this, m);
17549 this.calpopover.show(el);
17554 onLoad: function ()
17556 this.calevents = [];
17559 if(this.store.getCount() > 0){
17560 this.store.data.each(function(d){
17563 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17564 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17565 time : d.data.start_time,
17566 title : d.data.title,
17567 description : d.data.description,
17568 venue : d.data.venue
17573 this.renderEvents();
17575 if(this.calevents.length && this.loadMask){
17576 this.maskEl.hide();
17580 onBeforeLoad: function()
17582 this.clearEvents();
17584 this.maskEl.show();
17598 * @class Roo.bootstrap.Popover
17599 * @extends Roo.bootstrap.Component
17600 * Bootstrap Popover class
17601 * @cfg {String} html contents of the popover (or false to use children..)
17602 * @cfg {String} title of popover (or false to hide)
17603 * @cfg {String} placement how it is placed
17604 * @cfg {String} trigger click || hover (or false to trigger manually)
17605 * @cfg {String} over what (parent or false to trigger manually.)
17606 * @cfg {Number} delay - delay before showing
17609 * Create a new Popover
17610 * @param {Object} config The config object
17613 Roo.bootstrap.Popover = function(config){
17614 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17620 * After the popover show
17622 * @param {Roo.bootstrap.Popover} this
17627 * After the popover hide
17629 * @param {Roo.bootstrap.Popover} this
17635 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17637 title: 'Fill in a title',
17640 placement : 'right',
17641 trigger : 'hover', // hover
17647 can_build_overlaid : false,
17649 getChildContainer : function()
17651 return this.el.select('.popover-content',true).first();
17654 getAutoCreate : function(){
17657 cls : 'popover roo-dynamic',
17658 style: 'display:block',
17664 cls : 'popover-inner',
17668 cls: 'popover-title popover-header',
17672 cls : 'popover-content popover-body',
17683 setTitle: function(str)
17686 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17688 setContent: function(str)
17691 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17693 // as it get's added to the bottom of the page.
17694 onRender : function(ct, position)
17696 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17698 var cfg = Roo.apply({}, this.getAutoCreate());
17702 cfg.cls += ' ' + this.cls;
17705 cfg.style = this.style;
17707 //Roo.log("adding to ");
17708 this.el = Roo.get(document.body).createChild(cfg, position);
17709 // Roo.log(this.el);
17714 initEvents : function()
17716 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17717 this.el.enableDisplayMode('block');
17719 if (this.over === false) {
17722 if (this.triggers === false) {
17725 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17726 var triggers = this.trigger ? this.trigger.split(' ') : [];
17727 Roo.each(triggers, function(trigger) {
17729 if (trigger == 'click') {
17730 on_el.on('click', this.toggle, this);
17731 } else if (trigger != 'manual') {
17732 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17733 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17735 on_el.on(eventIn ,this.enter, this);
17736 on_el.on(eventOut, this.leave, this);
17747 toggle : function () {
17748 this.hoverState == 'in' ? this.leave() : this.enter();
17751 enter : function () {
17753 clearTimeout(this.timeout);
17755 this.hoverState = 'in';
17757 if (!this.delay || !this.delay.show) {
17762 this.timeout = setTimeout(function () {
17763 if (_t.hoverState == 'in') {
17766 }, this.delay.show)
17769 leave : function() {
17770 clearTimeout(this.timeout);
17772 this.hoverState = 'out';
17774 if (!this.delay || !this.delay.hide) {
17779 this.timeout = setTimeout(function () {
17780 if (_t.hoverState == 'out') {
17783 }, this.delay.hide)
17786 show : function (on_el)
17789 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17793 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17794 if (this.html !== false) {
17795 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17797 this.el.removeClass([
17798 'fade','top','bottom', 'left', 'right','in',
17799 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17801 if (!this.title.length) {
17802 this.el.select('.popover-title',true).hide();
17805 var placement = typeof this.placement == 'function' ?
17806 this.placement.call(this, this.el, on_el) :
17809 var autoToken = /\s?auto?\s?/i;
17810 var autoPlace = autoToken.test(placement);
17812 placement = placement.replace(autoToken, '') || 'top';
17816 //this.el.setXY([0,0]);
17818 this.el.dom.style.display='block';
17819 this.el.addClass(placement);
17821 //this.el.appendTo(on_el);
17823 var p = this.getPosition();
17824 var box = this.el.getBox();
17829 var align = Roo.bootstrap.Popover.alignment[placement];
17832 this.el.alignTo(on_el, align[0],align[1]);
17833 //var arrow = this.el.select('.arrow',true).first();
17834 //arrow.set(align[2],
17836 this.el.addClass('in');
17839 if (this.el.hasClass('fade')) {
17843 this.hoverState = 'in';
17845 this.fireEvent('show', this);
17850 this.el.setXY([0,0]);
17851 this.el.removeClass('in');
17853 this.hoverState = null;
17855 this.fireEvent('hide', this);
17860 Roo.bootstrap.Popover.alignment = {
17861 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17862 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17863 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17864 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17875 * @class Roo.bootstrap.Progress
17876 * @extends Roo.bootstrap.Component
17877 * Bootstrap Progress class
17878 * @cfg {Boolean} striped striped of the progress bar
17879 * @cfg {Boolean} active animated of the progress bar
17883 * Create a new Progress
17884 * @param {Object} config The config object
17887 Roo.bootstrap.Progress = function(config){
17888 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17891 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17896 getAutoCreate : function(){
17904 cfg.cls += ' progress-striped';
17908 cfg.cls += ' active';
17927 * @class Roo.bootstrap.ProgressBar
17928 * @extends Roo.bootstrap.Component
17929 * Bootstrap ProgressBar class
17930 * @cfg {Number} aria_valuenow aria-value now
17931 * @cfg {Number} aria_valuemin aria-value min
17932 * @cfg {Number} aria_valuemax aria-value max
17933 * @cfg {String} label label for the progress bar
17934 * @cfg {String} panel (success | info | warning | danger )
17935 * @cfg {String} role role of the progress bar
17936 * @cfg {String} sr_only text
17940 * Create a new ProgressBar
17941 * @param {Object} config The config object
17944 Roo.bootstrap.ProgressBar = function(config){
17945 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17948 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17952 aria_valuemax : 100,
17958 getAutoCreate : function()
17963 cls: 'progress-bar',
17964 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17976 cfg.role = this.role;
17979 if(this.aria_valuenow){
17980 cfg['aria-valuenow'] = this.aria_valuenow;
17983 if(this.aria_valuemin){
17984 cfg['aria-valuemin'] = this.aria_valuemin;
17987 if(this.aria_valuemax){
17988 cfg['aria-valuemax'] = this.aria_valuemax;
17991 if(this.label && !this.sr_only){
17992 cfg.html = this.label;
17996 cfg.cls += ' progress-bar-' + this.panel;
18002 update : function(aria_valuenow)
18004 this.aria_valuenow = aria_valuenow;
18006 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18021 * @class Roo.bootstrap.TabGroup
18022 * @extends Roo.bootstrap.Column
18023 * Bootstrap Column class
18024 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18025 * @cfg {Boolean} carousel true to make the group behave like a carousel
18026 * @cfg {Boolean} bullets show bullets for the panels
18027 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18028 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18029 * @cfg {Boolean} showarrow (true|false) show arrow default true
18032 * Create a new TabGroup
18033 * @param {Object} config The config object
18036 Roo.bootstrap.TabGroup = function(config){
18037 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18039 this.navId = Roo.id();
18042 Roo.bootstrap.TabGroup.register(this);
18046 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18049 transition : false,
18054 slideOnTouch : false,
18057 getAutoCreate : function()
18059 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18061 cfg.cls += ' tab-content';
18063 if (this.carousel) {
18064 cfg.cls += ' carousel slide';
18067 cls : 'carousel-inner',
18071 if(this.bullets && !Roo.isTouch){
18074 cls : 'carousel-bullets',
18078 if(this.bullets_cls){
18079 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18086 cfg.cn[0].cn.push(bullets);
18089 if(this.showarrow){
18090 cfg.cn[0].cn.push({
18092 class : 'carousel-arrow',
18096 class : 'carousel-prev',
18100 class : 'fa fa-chevron-left'
18106 class : 'carousel-next',
18110 class : 'fa fa-chevron-right'
18123 initEvents: function()
18125 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18126 // this.el.on("touchstart", this.onTouchStart, this);
18129 if(this.autoslide){
18132 this.slideFn = window.setInterval(function() {
18133 _this.showPanelNext();
18137 if(this.showarrow){
18138 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18139 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18145 // onTouchStart : function(e, el, o)
18147 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18151 // this.showPanelNext();
18155 getChildContainer : function()
18157 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18161 * register a Navigation item
18162 * @param {Roo.bootstrap.NavItem} the navitem to add
18164 register : function(item)
18166 this.tabs.push( item);
18167 item.navId = this.navId; // not really needed..
18172 getActivePanel : function()
18175 Roo.each(this.tabs, function(t) {
18185 getPanelByName : function(n)
18188 Roo.each(this.tabs, function(t) {
18189 if (t.tabId == n) {
18197 indexOfPanel : function(p)
18200 Roo.each(this.tabs, function(t,i) {
18201 if (t.tabId == p.tabId) {
18210 * show a specific panel
18211 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18212 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18214 showPanel : function (pan)
18216 if(this.transition || typeof(pan) == 'undefined'){
18217 Roo.log("waiting for the transitionend");
18221 if (typeof(pan) == 'number') {
18222 pan = this.tabs[pan];
18225 if (typeof(pan) == 'string') {
18226 pan = this.getPanelByName(pan);
18229 var cur = this.getActivePanel();
18232 Roo.log('pan or acitve pan is undefined');
18236 if (pan.tabId == this.getActivePanel().tabId) {
18240 if (false === cur.fireEvent('beforedeactivate')) {
18244 if(this.bullets > 0 && !Roo.isTouch){
18245 this.setActiveBullet(this.indexOfPanel(pan));
18248 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18250 this.transition = true;
18251 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18252 var lr = dir == 'next' ? 'left' : 'right';
18253 pan.el.addClass(dir); // or prev
18254 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18255 cur.el.addClass(lr); // or right
18256 pan.el.addClass(lr);
18259 cur.el.on('transitionend', function() {
18260 Roo.log("trans end?");
18262 pan.el.removeClass([lr,dir]);
18263 pan.setActive(true);
18265 cur.el.removeClass([lr]);
18266 cur.setActive(false);
18268 _this.transition = false;
18270 }, this, { single: true } );
18275 cur.setActive(false);
18276 pan.setActive(true);
18281 showPanelNext : function()
18283 var i = this.indexOfPanel(this.getActivePanel());
18285 if (i >= this.tabs.length - 1 && !this.autoslide) {
18289 if (i >= this.tabs.length - 1 && this.autoslide) {
18293 this.showPanel(this.tabs[i+1]);
18296 showPanelPrev : function()
18298 var i = this.indexOfPanel(this.getActivePanel());
18300 if (i < 1 && !this.autoslide) {
18304 if (i < 1 && this.autoslide) {
18305 i = this.tabs.length;
18308 this.showPanel(this.tabs[i-1]);
18312 addBullet: function()
18314 if(!this.bullets || Roo.isTouch){
18317 var ctr = this.el.select('.carousel-bullets',true).first();
18318 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18319 var bullet = ctr.createChild({
18320 cls : 'bullet bullet-' + i
18321 },ctr.dom.lastChild);
18326 bullet.on('click', (function(e, el, o, ii, t){
18328 e.preventDefault();
18330 this.showPanel(ii);
18332 if(this.autoslide && this.slideFn){
18333 clearInterval(this.slideFn);
18334 this.slideFn = window.setInterval(function() {
18335 _this.showPanelNext();
18339 }).createDelegate(this, [i, bullet], true));
18344 setActiveBullet : function(i)
18350 Roo.each(this.el.select('.bullet', true).elements, function(el){
18351 el.removeClass('selected');
18354 var bullet = this.el.select('.bullet-' + i, true).first();
18360 bullet.addClass('selected');
18371 Roo.apply(Roo.bootstrap.TabGroup, {
18375 * register a Navigation Group
18376 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18378 register : function(navgrp)
18380 this.groups[navgrp.navId] = navgrp;
18384 * fetch a Navigation Group based on the navigation ID
18385 * if one does not exist , it will get created.
18386 * @param {string} the navgroup to add
18387 * @returns {Roo.bootstrap.NavGroup} the navgroup
18389 get: function(navId) {
18390 if (typeof(this.groups[navId]) == 'undefined') {
18391 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18393 return this.groups[navId] ;
18408 * @class Roo.bootstrap.TabPanel
18409 * @extends Roo.bootstrap.Component
18410 * Bootstrap TabPanel class
18411 * @cfg {Boolean} active panel active
18412 * @cfg {String} html panel content
18413 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18414 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18415 * @cfg {String} href click to link..
18419 * Create a new TabPanel
18420 * @param {Object} config The config object
18423 Roo.bootstrap.TabPanel = function(config){
18424 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18428 * Fires when the active status changes
18429 * @param {Roo.bootstrap.TabPanel} this
18430 * @param {Boolean} state the new state
18435 * @event beforedeactivate
18436 * Fires before a tab is de-activated - can be used to do validation on a form.
18437 * @param {Roo.bootstrap.TabPanel} this
18438 * @return {Boolean} false if there is an error
18441 'beforedeactivate': true
18444 this.tabId = this.tabId || Roo.id();
18448 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18456 getAutoCreate : function(){
18459 // item is needed for carousel - not sure if it has any effect otherwise
18460 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18461 html: this.html || ''
18465 cfg.cls += ' active';
18469 cfg.tabId = this.tabId;
18476 initEvents: function()
18478 var p = this.parent();
18480 this.navId = this.navId || p.navId;
18482 if (typeof(this.navId) != 'undefined') {
18483 // not really needed.. but just in case.. parent should be a NavGroup.
18484 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18488 var i = tg.tabs.length - 1;
18490 if(this.active && tg.bullets > 0 && i < tg.bullets){
18491 tg.setActiveBullet(i);
18495 this.el.on('click', this.onClick, this);
18498 this.el.on("touchstart", this.onTouchStart, this);
18499 this.el.on("touchmove", this.onTouchMove, this);
18500 this.el.on("touchend", this.onTouchEnd, this);
18505 onRender : function(ct, position)
18507 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18510 setActive : function(state)
18512 Roo.log("panel - set active " + this.tabId + "=" + state);
18514 this.active = state;
18516 this.el.removeClass('active');
18518 } else if (!this.el.hasClass('active')) {
18519 this.el.addClass('active');
18522 this.fireEvent('changed', this, state);
18525 onClick : function(e)
18527 e.preventDefault();
18529 if(!this.href.length){
18533 window.location.href = this.href;
18542 onTouchStart : function(e)
18544 this.swiping = false;
18546 this.startX = e.browserEvent.touches[0].clientX;
18547 this.startY = e.browserEvent.touches[0].clientY;
18550 onTouchMove : function(e)
18552 this.swiping = true;
18554 this.endX = e.browserEvent.touches[0].clientX;
18555 this.endY = e.browserEvent.touches[0].clientY;
18558 onTouchEnd : function(e)
18565 var tabGroup = this.parent();
18567 if(this.endX > this.startX){ // swiping right
18568 tabGroup.showPanelPrev();
18572 if(this.startX > this.endX){ // swiping left
18573 tabGroup.showPanelNext();
18592 * @class Roo.bootstrap.DateField
18593 * @extends Roo.bootstrap.Input
18594 * Bootstrap DateField class
18595 * @cfg {Number} weekStart default 0
18596 * @cfg {String} viewMode default empty, (months|years)
18597 * @cfg {String} minViewMode default empty, (months|years)
18598 * @cfg {Number} startDate default -Infinity
18599 * @cfg {Number} endDate default Infinity
18600 * @cfg {Boolean} todayHighlight default false
18601 * @cfg {Boolean} todayBtn default false
18602 * @cfg {Boolean} calendarWeeks default false
18603 * @cfg {Object} daysOfWeekDisabled default empty
18604 * @cfg {Boolean} singleMode default false (true | false)
18606 * @cfg {Boolean} keyboardNavigation default true
18607 * @cfg {String} language default en
18610 * Create a new DateField
18611 * @param {Object} config The config object
18614 Roo.bootstrap.DateField = function(config){
18615 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18619 * Fires when this field show.
18620 * @param {Roo.bootstrap.DateField} this
18621 * @param {Mixed} date The date value
18626 * Fires when this field hide.
18627 * @param {Roo.bootstrap.DateField} this
18628 * @param {Mixed} date The date value
18633 * Fires when select a date.
18634 * @param {Roo.bootstrap.DateField} this
18635 * @param {Mixed} date The date value
18639 * @event beforeselect
18640 * Fires when before select a date.
18641 * @param {Roo.bootstrap.DateField} this
18642 * @param {Mixed} date The date value
18644 beforeselect : true
18648 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18651 * @cfg {String} format
18652 * The default date format string which can be overriden for localization support. The format must be
18653 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18657 * @cfg {String} altFormats
18658 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18659 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18661 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18669 todayHighlight : false,
18675 keyboardNavigation: true,
18677 calendarWeeks: false,
18679 startDate: -Infinity,
18683 daysOfWeekDisabled: [],
18687 singleMode : false,
18689 UTCDate: function()
18691 return new Date(Date.UTC.apply(Date, arguments));
18694 UTCToday: function()
18696 var today = new Date();
18697 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18700 getDate: function() {
18701 var d = this.getUTCDate();
18702 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18705 getUTCDate: function() {
18709 setDate: function(d) {
18710 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18713 setUTCDate: function(d) {
18715 this.setValue(this.formatDate(this.date));
18718 onRender: function(ct, position)
18721 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18723 this.language = this.language || 'en';
18724 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18725 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18727 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18728 this.format = this.format || 'm/d/y';
18729 this.isInline = false;
18730 this.isInput = true;
18731 this.component = this.el.select('.add-on', true).first() || false;
18732 this.component = (this.component && this.component.length === 0) ? false : this.component;
18733 this.hasInput = this.component && this.inputEl().length;
18735 if (typeof(this.minViewMode === 'string')) {
18736 switch (this.minViewMode) {
18738 this.minViewMode = 1;
18741 this.minViewMode = 2;
18744 this.minViewMode = 0;
18749 if (typeof(this.viewMode === 'string')) {
18750 switch (this.viewMode) {
18763 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18765 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18767 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18769 this.picker().on('mousedown', this.onMousedown, this);
18770 this.picker().on('click', this.onClick, this);
18772 this.picker().addClass('datepicker-dropdown');
18774 this.startViewMode = this.viewMode;
18776 if(this.singleMode){
18777 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18778 v.setVisibilityMode(Roo.Element.DISPLAY);
18782 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18783 v.setStyle('width', '189px');
18787 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18788 if(!this.calendarWeeks){
18793 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18794 v.attr('colspan', function(i, val){
18795 return parseInt(val) + 1;
18800 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18802 this.setStartDate(this.startDate);
18803 this.setEndDate(this.endDate);
18805 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18812 if(this.isInline) {
18817 picker : function()
18819 return this.pickerEl;
18820 // return this.el.select('.datepicker', true).first();
18823 fillDow: function()
18825 var dowCnt = this.weekStart;
18834 if(this.calendarWeeks){
18842 while (dowCnt < this.weekStart + 7) {
18846 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18850 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18853 fillMonths: function()
18856 var months = this.picker().select('>.datepicker-months td', true).first();
18858 months.dom.innerHTML = '';
18864 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18867 months.createChild(month);
18874 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;
18876 if (this.date < this.startDate) {
18877 this.viewDate = new Date(this.startDate);
18878 } else if (this.date > this.endDate) {
18879 this.viewDate = new Date(this.endDate);
18881 this.viewDate = new Date(this.date);
18889 var d = new Date(this.viewDate),
18890 year = d.getUTCFullYear(),
18891 month = d.getUTCMonth(),
18892 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18893 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18894 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18895 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18896 currentDate = this.date && this.date.valueOf(),
18897 today = this.UTCToday();
18899 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18901 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18903 // this.picker.select('>tfoot th.today').
18904 // .text(dates[this.language].today)
18905 // .toggle(this.todayBtn !== false);
18907 this.updateNavArrows();
18910 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18912 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18914 prevMonth.setUTCDate(day);
18916 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18918 var nextMonth = new Date(prevMonth);
18920 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18922 nextMonth = nextMonth.valueOf();
18924 var fillMonths = false;
18926 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18928 while(prevMonth.valueOf() <= nextMonth) {
18931 if (prevMonth.getUTCDay() === this.weekStart) {
18933 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18941 if(this.calendarWeeks){
18942 // ISO 8601: First week contains first thursday.
18943 // ISO also states week starts on Monday, but we can be more abstract here.
18945 // Start of current week: based on weekstart/current date
18946 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18947 // Thursday of this week
18948 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18949 // First Thursday of year, year from thursday
18950 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18951 // Calendar week: ms between thursdays, div ms per day, div 7 days
18952 calWeek = (th - yth) / 864e5 / 7 + 1;
18954 fillMonths.cn.push({
18962 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18964 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18967 if (this.todayHighlight &&
18968 prevMonth.getUTCFullYear() == today.getFullYear() &&
18969 prevMonth.getUTCMonth() == today.getMonth() &&
18970 prevMonth.getUTCDate() == today.getDate()) {
18971 clsName += ' today';
18974 if (currentDate && prevMonth.valueOf() === currentDate) {
18975 clsName += ' active';
18978 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18979 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18980 clsName += ' disabled';
18983 fillMonths.cn.push({
18985 cls: 'day ' + clsName,
18986 html: prevMonth.getDate()
18989 prevMonth.setDate(prevMonth.getDate()+1);
18992 var currentYear = this.date && this.date.getUTCFullYear();
18993 var currentMonth = this.date && this.date.getUTCMonth();
18995 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18997 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18998 v.removeClass('active');
19000 if(currentYear === year && k === currentMonth){
19001 v.addClass('active');
19004 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19005 v.addClass('disabled');
19011 year = parseInt(year/10, 10) * 10;
19013 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19015 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19018 for (var i = -1; i < 11; i++) {
19019 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19021 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19029 showMode: function(dir)
19032 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19035 Roo.each(this.picker().select('>div',true).elements, function(v){
19036 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19039 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19044 if(this.isInline) {
19048 this.picker().removeClass(['bottom', 'top']);
19050 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19052 * place to the top of element!
19056 this.picker().addClass('top');
19057 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19062 this.picker().addClass('bottom');
19064 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19067 parseDate : function(value)
19069 if(!value || value instanceof Date){
19072 var v = Date.parseDate(value, this.format);
19073 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19074 v = Date.parseDate(value, 'Y-m-d');
19076 if(!v && this.altFormats){
19077 if(!this.altFormatsArray){
19078 this.altFormatsArray = this.altFormats.split("|");
19080 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19081 v = Date.parseDate(value, this.altFormatsArray[i]);
19087 formatDate : function(date, fmt)
19089 return (!date || !(date instanceof Date)) ?
19090 date : date.dateFormat(fmt || this.format);
19093 onFocus : function()
19095 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19099 onBlur : function()
19101 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19103 var d = this.inputEl().getValue();
19110 showPopup : function()
19112 this.picker().show();
19116 this.fireEvent('showpopup', this, this.date);
19119 hidePopup : function()
19121 if(this.isInline) {
19124 this.picker().hide();
19125 this.viewMode = this.startViewMode;
19128 this.fireEvent('hidepopup', this, this.date);
19132 onMousedown: function(e)
19134 e.stopPropagation();
19135 e.preventDefault();
19140 Roo.bootstrap.DateField.superclass.keyup.call(this);
19144 setValue: function(v)
19146 if(this.fireEvent('beforeselect', this, v) !== false){
19147 var d = new Date(this.parseDate(v) ).clearTime();
19149 if(isNaN(d.getTime())){
19150 this.date = this.viewDate = '';
19151 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19155 v = this.formatDate(d);
19157 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19159 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19163 this.fireEvent('select', this, this.date);
19167 getValue: function()
19169 return this.formatDate(this.date);
19172 fireKey: function(e)
19174 if (!this.picker().isVisible()){
19175 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19181 var dateChanged = false,
19183 newDate, newViewDate;
19188 e.preventDefault();
19192 if (!this.keyboardNavigation) {
19195 dir = e.keyCode == 37 ? -1 : 1;
19198 newDate = this.moveYear(this.date, dir);
19199 newViewDate = this.moveYear(this.viewDate, dir);
19200 } else if (e.shiftKey){
19201 newDate = this.moveMonth(this.date, dir);
19202 newViewDate = this.moveMonth(this.viewDate, dir);
19204 newDate = new Date(this.date);
19205 newDate.setUTCDate(this.date.getUTCDate() + dir);
19206 newViewDate = new Date(this.viewDate);
19207 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19209 if (this.dateWithinRange(newDate)){
19210 this.date = newDate;
19211 this.viewDate = newViewDate;
19212 this.setValue(this.formatDate(this.date));
19214 e.preventDefault();
19215 dateChanged = true;
19220 if (!this.keyboardNavigation) {
19223 dir = e.keyCode == 38 ? -1 : 1;
19225 newDate = this.moveYear(this.date, dir);
19226 newViewDate = this.moveYear(this.viewDate, dir);
19227 } else if (e.shiftKey){
19228 newDate = this.moveMonth(this.date, dir);
19229 newViewDate = this.moveMonth(this.viewDate, dir);
19231 newDate = new Date(this.date);
19232 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19233 newViewDate = new Date(this.viewDate);
19234 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19236 if (this.dateWithinRange(newDate)){
19237 this.date = newDate;
19238 this.viewDate = newViewDate;
19239 this.setValue(this.formatDate(this.date));
19241 e.preventDefault();
19242 dateChanged = true;
19246 this.setValue(this.formatDate(this.date));
19248 e.preventDefault();
19251 this.setValue(this.formatDate(this.date));
19265 onClick: function(e)
19267 e.stopPropagation();
19268 e.preventDefault();
19270 var target = e.getTarget();
19272 if(target.nodeName.toLowerCase() === 'i'){
19273 target = Roo.get(target).dom.parentNode;
19276 var nodeName = target.nodeName;
19277 var className = target.className;
19278 var html = target.innerHTML;
19279 //Roo.log(nodeName);
19281 switch(nodeName.toLowerCase()) {
19283 switch(className) {
19289 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19290 switch(this.viewMode){
19292 this.viewDate = this.moveMonth(this.viewDate, dir);
19296 this.viewDate = this.moveYear(this.viewDate, dir);
19302 var date = new Date();
19303 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19305 this.setValue(this.formatDate(this.date));
19312 if (className.indexOf('disabled') < 0) {
19313 this.viewDate.setUTCDate(1);
19314 if (className.indexOf('month') > -1) {
19315 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19317 var year = parseInt(html, 10) || 0;
19318 this.viewDate.setUTCFullYear(year);
19322 if(this.singleMode){
19323 this.setValue(this.formatDate(this.viewDate));
19334 //Roo.log(className);
19335 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19336 var day = parseInt(html, 10) || 1;
19337 var year = this.viewDate.getUTCFullYear(),
19338 month = this.viewDate.getUTCMonth();
19340 if (className.indexOf('old') > -1) {
19347 } else if (className.indexOf('new') > -1) {
19355 //Roo.log([year,month,day]);
19356 this.date = this.UTCDate(year, month, day,0,0,0,0);
19357 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19359 //Roo.log(this.formatDate(this.date));
19360 this.setValue(this.formatDate(this.date));
19367 setStartDate: function(startDate)
19369 this.startDate = startDate || -Infinity;
19370 if (this.startDate !== -Infinity) {
19371 this.startDate = this.parseDate(this.startDate);
19374 this.updateNavArrows();
19377 setEndDate: function(endDate)
19379 this.endDate = endDate || Infinity;
19380 if (this.endDate !== Infinity) {
19381 this.endDate = this.parseDate(this.endDate);
19384 this.updateNavArrows();
19387 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19389 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19390 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19391 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19393 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19394 return parseInt(d, 10);
19397 this.updateNavArrows();
19400 updateNavArrows: function()
19402 if(this.singleMode){
19406 var d = new Date(this.viewDate),
19407 year = d.getUTCFullYear(),
19408 month = d.getUTCMonth();
19410 Roo.each(this.picker().select('.prev', true).elements, function(v){
19412 switch (this.viewMode) {
19415 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19421 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19428 Roo.each(this.picker().select('.next', true).elements, function(v){
19430 switch (this.viewMode) {
19433 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19439 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19447 moveMonth: function(date, dir)
19452 var new_date = new Date(date.valueOf()),
19453 day = new_date.getUTCDate(),
19454 month = new_date.getUTCMonth(),
19455 mag = Math.abs(dir),
19457 dir = dir > 0 ? 1 : -1;
19460 // If going back one month, make sure month is not current month
19461 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19463 return new_date.getUTCMonth() == month;
19465 // If going forward one month, make sure month is as expected
19466 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19468 return new_date.getUTCMonth() != new_month;
19470 new_month = month + dir;
19471 new_date.setUTCMonth(new_month);
19472 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19473 if (new_month < 0 || new_month > 11) {
19474 new_month = (new_month + 12) % 12;
19477 // For magnitudes >1, move one month at a time...
19478 for (var i=0; i<mag; i++) {
19479 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19480 new_date = this.moveMonth(new_date, dir);
19482 // ...then reset the day, keeping it in the new month
19483 new_month = new_date.getUTCMonth();
19484 new_date.setUTCDate(day);
19486 return new_month != new_date.getUTCMonth();
19489 // Common date-resetting loop -- if date is beyond end of month, make it
19492 new_date.setUTCDate(--day);
19493 new_date.setUTCMonth(new_month);
19498 moveYear: function(date, dir)
19500 return this.moveMonth(date, dir*12);
19503 dateWithinRange: function(date)
19505 return date >= this.startDate && date <= this.endDate;
19511 this.picker().remove();
19514 validateValue : function(value)
19516 if(this.getVisibilityEl().hasClass('hidden')){
19520 if(value.length < 1) {
19521 if(this.allowBlank){
19527 if(value.length < this.minLength){
19530 if(value.length > this.maxLength){
19534 var vt = Roo.form.VTypes;
19535 if(!vt[this.vtype](value, this)){
19539 if(typeof this.validator == "function"){
19540 var msg = this.validator(value);
19546 if(this.regex && !this.regex.test(value)){
19550 if(typeof(this.parseDate(value)) == 'undefined'){
19554 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19558 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19568 this.date = this.viewDate = '';
19570 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19575 Roo.apply(Roo.bootstrap.DateField, {
19586 html: '<i class="fa fa-arrow-left"/>'
19596 html: '<i class="fa fa-arrow-right"/>'
19638 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19639 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19640 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19641 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19642 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19655 navFnc: 'FullYear',
19660 navFnc: 'FullYear',
19665 Roo.apply(Roo.bootstrap.DateField, {
19669 cls: 'datepicker dropdown-menu roo-dynamic',
19673 cls: 'datepicker-days',
19677 cls: 'table-condensed',
19679 Roo.bootstrap.DateField.head,
19683 Roo.bootstrap.DateField.footer
19690 cls: 'datepicker-months',
19694 cls: 'table-condensed',
19696 Roo.bootstrap.DateField.head,
19697 Roo.bootstrap.DateField.content,
19698 Roo.bootstrap.DateField.footer
19705 cls: 'datepicker-years',
19709 cls: 'table-condensed',
19711 Roo.bootstrap.DateField.head,
19712 Roo.bootstrap.DateField.content,
19713 Roo.bootstrap.DateField.footer
19732 * @class Roo.bootstrap.TimeField
19733 * @extends Roo.bootstrap.Input
19734 * Bootstrap DateField class
19738 * Create a new TimeField
19739 * @param {Object} config The config object
19742 Roo.bootstrap.TimeField = function(config){
19743 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19747 * Fires when this field show.
19748 * @param {Roo.bootstrap.DateField} thisthis
19749 * @param {Mixed} date The date value
19754 * Fires when this field hide.
19755 * @param {Roo.bootstrap.DateField} this
19756 * @param {Mixed} date The date value
19761 * Fires when select a date.
19762 * @param {Roo.bootstrap.DateField} this
19763 * @param {Mixed} date The date value
19769 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19772 * @cfg {String} format
19773 * The default time format string which can be overriden for localization support. The format must be
19774 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19778 onRender: function(ct, position)
19781 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19783 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19785 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19787 this.pop = this.picker().select('>.datepicker-time',true).first();
19788 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19790 this.picker().on('mousedown', this.onMousedown, this);
19791 this.picker().on('click', this.onClick, this);
19793 this.picker().addClass('datepicker-dropdown');
19798 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19799 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19800 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19801 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19802 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19803 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19807 fireKey: function(e){
19808 if (!this.picker().isVisible()){
19809 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19815 e.preventDefault();
19823 this.onTogglePeriod();
19826 this.onIncrementMinutes();
19829 this.onDecrementMinutes();
19838 onClick: function(e) {
19839 e.stopPropagation();
19840 e.preventDefault();
19843 picker : function()
19845 return this.el.select('.datepicker', true).first();
19848 fillTime: function()
19850 var time = this.pop.select('tbody', true).first();
19852 time.dom.innerHTML = '';
19867 cls: 'hours-up glyphicon glyphicon-chevron-up'
19887 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19908 cls: 'timepicker-hour',
19923 cls: 'timepicker-minute',
19938 cls: 'btn btn-primary period',
19960 cls: 'hours-down glyphicon glyphicon-chevron-down'
19980 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19998 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20005 var hours = this.time.getHours();
20006 var minutes = this.time.getMinutes();
20019 hours = hours - 12;
20023 hours = '0' + hours;
20027 minutes = '0' + minutes;
20030 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20031 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20032 this.pop.select('button', true).first().dom.innerHTML = period;
20038 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20040 var cls = ['bottom'];
20042 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20049 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20054 this.picker().addClass(cls.join('-'));
20058 Roo.each(cls, function(c){
20060 _this.picker().setTop(_this.inputEl().getHeight());
20064 _this.picker().setTop(0 - _this.picker().getHeight());
20069 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20073 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20080 onFocus : function()
20082 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20086 onBlur : function()
20088 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20094 this.picker().show();
20099 this.fireEvent('show', this, this.date);
20104 this.picker().hide();
20107 this.fireEvent('hide', this, this.date);
20110 setTime : function()
20113 this.setValue(this.time.format(this.format));
20115 this.fireEvent('select', this, this.date);
20120 onMousedown: function(e){
20121 e.stopPropagation();
20122 e.preventDefault();
20125 onIncrementHours: function()
20127 Roo.log('onIncrementHours');
20128 this.time = this.time.add(Date.HOUR, 1);
20133 onDecrementHours: function()
20135 Roo.log('onDecrementHours');
20136 this.time = this.time.add(Date.HOUR, -1);
20140 onIncrementMinutes: function()
20142 Roo.log('onIncrementMinutes');
20143 this.time = this.time.add(Date.MINUTE, 1);
20147 onDecrementMinutes: function()
20149 Roo.log('onDecrementMinutes');
20150 this.time = this.time.add(Date.MINUTE, -1);
20154 onTogglePeriod: function()
20156 Roo.log('onTogglePeriod');
20157 this.time = this.time.add(Date.HOUR, 12);
20164 Roo.apply(Roo.bootstrap.TimeField, {
20194 cls: 'btn btn-info ok',
20206 Roo.apply(Roo.bootstrap.TimeField, {
20210 cls: 'datepicker dropdown-menu',
20214 cls: 'datepicker-time',
20218 cls: 'table-condensed',
20220 Roo.bootstrap.TimeField.content,
20221 Roo.bootstrap.TimeField.footer
20240 * @class Roo.bootstrap.MonthField
20241 * @extends Roo.bootstrap.Input
20242 * Bootstrap MonthField class
20244 * @cfg {String} language default en
20247 * Create a new MonthField
20248 * @param {Object} config The config object
20251 Roo.bootstrap.MonthField = function(config){
20252 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20257 * Fires when this field show.
20258 * @param {Roo.bootstrap.MonthField} this
20259 * @param {Mixed} date The date value
20264 * Fires when this field hide.
20265 * @param {Roo.bootstrap.MonthField} this
20266 * @param {Mixed} date The date value
20271 * Fires when select a date.
20272 * @param {Roo.bootstrap.MonthField} this
20273 * @param {String} oldvalue The old value
20274 * @param {String} newvalue The new value
20280 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20282 onRender: function(ct, position)
20285 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20287 this.language = this.language || 'en';
20288 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20289 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20291 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20292 this.isInline = false;
20293 this.isInput = true;
20294 this.component = this.el.select('.add-on', true).first() || false;
20295 this.component = (this.component && this.component.length === 0) ? false : this.component;
20296 this.hasInput = this.component && this.inputEL().length;
20298 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20300 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20302 this.picker().on('mousedown', this.onMousedown, this);
20303 this.picker().on('click', this.onClick, this);
20305 this.picker().addClass('datepicker-dropdown');
20307 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20308 v.setStyle('width', '189px');
20315 if(this.isInline) {
20321 setValue: function(v, suppressEvent)
20323 var o = this.getValue();
20325 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20329 if(suppressEvent !== true){
20330 this.fireEvent('select', this, o, v);
20335 getValue: function()
20340 onClick: function(e)
20342 e.stopPropagation();
20343 e.preventDefault();
20345 var target = e.getTarget();
20347 if(target.nodeName.toLowerCase() === 'i'){
20348 target = Roo.get(target).dom.parentNode;
20351 var nodeName = target.nodeName;
20352 var className = target.className;
20353 var html = target.innerHTML;
20355 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20359 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20361 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20367 picker : function()
20369 return this.pickerEl;
20372 fillMonths: function()
20375 var months = this.picker().select('>.datepicker-months td', true).first();
20377 months.dom.innerHTML = '';
20383 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20386 months.createChild(month);
20395 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20396 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20399 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20400 e.removeClass('active');
20402 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20403 e.addClass('active');
20410 if(this.isInline) {
20414 this.picker().removeClass(['bottom', 'top']);
20416 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20418 * place to the top of element!
20422 this.picker().addClass('top');
20423 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20428 this.picker().addClass('bottom');
20430 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20433 onFocus : function()
20435 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20439 onBlur : function()
20441 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20443 var d = this.inputEl().getValue();
20452 this.picker().show();
20453 this.picker().select('>.datepicker-months', true).first().show();
20457 this.fireEvent('show', this, this.date);
20462 if(this.isInline) {
20465 this.picker().hide();
20466 this.fireEvent('hide', this, this.date);
20470 onMousedown: function(e)
20472 e.stopPropagation();
20473 e.preventDefault();
20478 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20482 fireKey: function(e)
20484 if (!this.picker().isVisible()){
20485 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20496 e.preventDefault();
20500 dir = e.keyCode == 37 ? -1 : 1;
20502 this.vIndex = this.vIndex + dir;
20504 if(this.vIndex < 0){
20508 if(this.vIndex > 11){
20512 if(isNaN(this.vIndex)){
20516 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20522 dir = e.keyCode == 38 ? -1 : 1;
20524 this.vIndex = this.vIndex + dir * 4;
20526 if(this.vIndex < 0){
20530 if(this.vIndex > 11){
20534 if(isNaN(this.vIndex)){
20538 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20543 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20544 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20548 e.preventDefault();
20551 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20552 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20568 this.picker().remove();
20573 Roo.apply(Roo.bootstrap.MonthField, {
20592 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20593 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20598 Roo.apply(Roo.bootstrap.MonthField, {
20602 cls: 'datepicker dropdown-menu roo-dynamic',
20606 cls: 'datepicker-months',
20610 cls: 'table-condensed',
20612 Roo.bootstrap.DateField.content
20632 * @class Roo.bootstrap.CheckBox
20633 * @extends Roo.bootstrap.Input
20634 * Bootstrap CheckBox class
20636 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20637 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20638 * @cfg {String} boxLabel The text that appears beside the checkbox
20639 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20640 * @cfg {Boolean} checked initnal the element
20641 * @cfg {Boolean} inline inline the element (default false)
20642 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20643 * @cfg {String} tooltip label tooltip
20646 * Create a new CheckBox
20647 * @param {Object} config The config object
20650 Roo.bootstrap.CheckBox = function(config){
20651 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20656 * Fires when the element is checked or unchecked.
20657 * @param {Roo.bootstrap.CheckBox} this This input
20658 * @param {Boolean} checked The new checked value
20663 * Fires when the element is click.
20664 * @param {Roo.bootstrap.CheckBox} this This input
20671 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20673 inputType: 'checkbox',
20682 getAutoCreate : function()
20684 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20690 cfg.cls = 'form-group ' + this.inputType; //input-group
20693 cfg.cls += ' ' + this.inputType + '-inline';
20699 type : this.inputType,
20700 value : this.inputValue,
20701 cls : 'roo-' + this.inputType, //'form-box',
20702 placeholder : this.placeholder || ''
20706 if(this.inputType != 'radio'){
20710 cls : 'roo-hidden-value',
20711 value : this.checked ? this.inputValue : this.valueOff
20716 if (this.weight) { // Validity check?
20717 cfg.cls += " " + this.inputType + "-" + this.weight;
20720 if (this.disabled) {
20721 input.disabled=true;
20725 input.checked = this.checked;
20730 input.name = this.name;
20732 if(this.inputType != 'radio'){
20733 hidden.name = this.name;
20734 input.name = '_hidden_' + this.name;
20739 input.cls += ' input-' + this.size;
20744 ['xs','sm','md','lg'].map(function(size){
20745 if (settings[size]) {
20746 cfg.cls += ' col-' + size + '-' + settings[size];
20750 var inputblock = input;
20752 if (this.before || this.after) {
20755 cls : 'input-group',
20760 inputblock.cn.push({
20762 cls : 'input-group-addon',
20767 inputblock.cn.push(input);
20769 if(this.inputType != 'radio'){
20770 inputblock.cn.push(hidden);
20774 inputblock.cn.push({
20776 cls : 'input-group-addon',
20783 if (align ==='left' && this.fieldLabel.length) {
20784 // Roo.log("left and has label");
20789 cls : 'control-label',
20790 html : this.fieldLabel
20800 if(this.labelWidth > 12){
20801 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20804 if(this.labelWidth < 13 && this.labelmd == 0){
20805 this.labelmd = this.labelWidth;
20808 if(this.labellg > 0){
20809 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20810 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20813 if(this.labelmd > 0){
20814 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20815 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20818 if(this.labelsm > 0){
20819 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20820 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20823 if(this.labelxs > 0){
20824 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20825 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20828 } else if ( this.fieldLabel.length) {
20829 // Roo.log(" label");
20833 tag: this.boxLabel ? 'span' : 'label',
20835 cls: 'control-label box-input-label',
20836 //cls : 'input-group-addon',
20837 html : this.fieldLabel
20846 // Roo.log(" no label && no align");
20847 cfg.cn = [ inputblock ] ;
20853 var boxLabelCfg = {
20855 //'for': id, // box label is handled by onclick - so no for...
20857 html: this.boxLabel
20861 boxLabelCfg.tooltip = this.tooltip;
20864 cfg.cn.push(boxLabelCfg);
20867 if(this.inputType != 'radio'){
20868 cfg.cn.push(hidden);
20876 * return the real input element.
20878 inputEl: function ()
20880 return this.el.select('input.roo-' + this.inputType,true).first();
20882 hiddenEl: function ()
20884 return this.el.select('input.roo-hidden-value',true).first();
20887 labelEl: function()
20889 return this.el.select('label.control-label',true).first();
20891 /* depricated... */
20895 return this.labelEl();
20898 boxLabelEl: function()
20900 return this.el.select('label.box-label',true).first();
20903 initEvents : function()
20905 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20907 this.inputEl().on('click', this.onClick, this);
20909 if (this.boxLabel) {
20910 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20913 this.startValue = this.getValue();
20916 Roo.bootstrap.CheckBox.register(this);
20920 onClick : function(e)
20922 if(this.fireEvent('click', this, e) !== false){
20923 this.setChecked(!this.checked);
20928 setChecked : function(state,suppressEvent)
20930 this.startValue = this.getValue();
20932 if(this.inputType == 'radio'){
20934 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20935 e.dom.checked = false;
20938 this.inputEl().dom.checked = true;
20940 this.inputEl().dom.value = this.inputValue;
20942 if(suppressEvent !== true){
20943 this.fireEvent('check', this, true);
20951 this.checked = state;
20953 this.inputEl().dom.checked = state;
20956 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20958 if(suppressEvent !== true){
20959 this.fireEvent('check', this, state);
20965 getValue : function()
20967 if(this.inputType == 'radio'){
20968 return this.getGroupValue();
20971 return this.hiddenEl().dom.value;
20975 getGroupValue : function()
20977 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20981 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20984 setValue : function(v,suppressEvent)
20986 if(this.inputType == 'radio'){
20987 this.setGroupValue(v, suppressEvent);
20991 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20996 setGroupValue : function(v, suppressEvent)
20998 this.startValue = this.getValue();
21000 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21001 e.dom.checked = false;
21003 if(e.dom.value == v){
21004 e.dom.checked = true;
21008 if(suppressEvent !== true){
21009 this.fireEvent('check', this, true);
21017 validate : function()
21019 if(this.getVisibilityEl().hasClass('hidden')){
21025 (this.inputType == 'radio' && this.validateRadio()) ||
21026 (this.inputType == 'checkbox' && this.validateCheckbox())
21032 this.markInvalid();
21036 validateRadio : function()
21038 if(this.getVisibilityEl().hasClass('hidden')){
21042 if(this.allowBlank){
21048 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21049 if(!e.dom.checked){
21061 validateCheckbox : function()
21064 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21065 //return (this.getValue() == this.inputValue) ? true : false;
21068 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21076 for(var i in group){
21077 if(group[i].el.isVisible(true)){
21085 for(var i in group){
21090 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21097 * Mark this field as valid
21099 markValid : function()
21103 this.fireEvent('valid', this);
21105 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21108 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21115 if(this.inputType == 'radio'){
21116 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21117 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21118 e.findParent('.form-group', false, true).addClass(_this.validClass);
21125 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21126 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21130 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21136 for(var i in group){
21137 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21138 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21143 * Mark this field as invalid
21144 * @param {String} msg The validation message
21146 markInvalid : function(msg)
21148 if(this.allowBlank){
21154 this.fireEvent('invalid', this, msg);
21156 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21159 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21163 label.markInvalid();
21166 if(this.inputType == 'radio'){
21167 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21168 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21169 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21176 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21177 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21181 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21187 for(var i in group){
21188 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21189 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21194 clearInvalid : function()
21196 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21198 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21200 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21202 if (label && label.iconEl) {
21203 label.iconEl.removeClass(label.validClass);
21204 label.iconEl.removeClass(label.invalidClass);
21208 disable : function()
21210 if(this.inputType != 'radio'){
21211 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21218 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21219 _this.getActionEl().addClass(this.disabledClass);
21220 e.dom.disabled = true;
21224 this.disabled = true;
21225 this.fireEvent("disable", this);
21229 enable : function()
21231 if(this.inputType != 'radio'){
21232 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21239 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21240 _this.getActionEl().removeClass(this.disabledClass);
21241 e.dom.disabled = false;
21245 this.disabled = false;
21246 this.fireEvent("enable", this);
21250 setBoxLabel : function(v)
21255 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21261 Roo.apply(Roo.bootstrap.CheckBox, {
21266 * register a CheckBox Group
21267 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21269 register : function(checkbox)
21271 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21272 this.groups[checkbox.groupId] = {};
21275 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21279 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21283 * fetch a CheckBox Group based on the group ID
21284 * @param {string} the group ID
21285 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21287 get: function(groupId) {
21288 if (typeof(this.groups[groupId]) == 'undefined') {
21292 return this.groups[groupId] ;
21305 * @class Roo.bootstrap.Radio
21306 * @extends Roo.bootstrap.Component
21307 * Bootstrap Radio class
21308 * @cfg {String} boxLabel - the label associated
21309 * @cfg {String} value - the value of radio
21312 * Create a new Radio
21313 * @param {Object} config The config object
21315 Roo.bootstrap.Radio = function(config){
21316 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21320 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21326 getAutoCreate : function()
21330 cls : 'form-group radio',
21335 html : this.boxLabel
21343 initEvents : function()
21345 this.parent().register(this);
21347 this.el.on('click', this.onClick, this);
21351 onClick : function(e)
21353 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21354 this.setChecked(true);
21358 setChecked : function(state, suppressEvent)
21360 this.parent().setValue(this.value, suppressEvent);
21364 setBoxLabel : function(v)
21369 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21384 * @class Roo.bootstrap.SecurePass
21385 * @extends Roo.bootstrap.Input
21386 * Bootstrap SecurePass class
21390 * Create a new SecurePass
21391 * @param {Object} config The config object
21394 Roo.bootstrap.SecurePass = function (config) {
21395 // these go here, so the translation tool can replace them..
21397 PwdEmpty: "Please type a password, and then retype it to confirm.",
21398 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21399 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21400 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21401 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21402 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21403 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21404 TooWeak: "Your password is Too Weak."
21406 this.meterLabel = "Password strength:";
21407 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21408 this.meterClass = [
21409 "roo-password-meter-tooweak",
21410 "roo-password-meter-weak",
21411 "roo-password-meter-medium",
21412 "roo-password-meter-strong",
21413 "roo-password-meter-grey"
21418 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21421 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21423 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21425 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21426 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21427 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21428 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21429 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21430 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21431 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21441 * @cfg {String/Object} Label for the strength meter (defaults to
21442 * 'Password strength:')
21447 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21448 * ['Weak', 'Medium', 'Strong'])
21451 pwdStrengths: false,
21464 initEvents: function ()
21466 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21468 if (this.el.is('input[type=password]') && Roo.isSafari) {
21469 this.el.on('keydown', this.SafariOnKeyDown, this);
21472 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21475 onRender: function (ct, position)
21477 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21478 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21479 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21481 this.trigger.createChild({
21486 cls: 'roo-password-meter-grey col-xs-12',
21489 //width: this.meterWidth + 'px'
21493 cls: 'roo-password-meter-text'
21499 if (this.hideTrigger) {
21500 this.trigger.setDisplayed(false);
21502 this.setSize(this.width || '', this.height || '');
21505 onDestroy: function ()
21507 if (this.trigger) {
21508 this.trigger.removeAllListeners();
21509 this.trigger.remove();
21512 this.wrap.remove();
21514 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21517 checkStrength: function ()
21519 var pwd = this.inputEl().getValue();
21520 if (pwd == this._lastPwd) {
21525 if (this.ClientSideStrongPassword(pwd)) {
21527 } else if (this.ClientSideMediumPassword(pwd)) {
21529 } else if (this.ClientSideWeakPassword(pwd)) {
21535 Roo.log('strength1: ' + strength);
21537 //var pm = this.trigger.child('div/div/div').dom;
21538 var pm = this.trigger.child('div/div');
21539 pm.removeClass(this.meterClass);
21540 pm.addClass(this.meterClass[strength]);
21543 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21545 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21547 this._lastPwd = pwd;
21551 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21553 this._lastPwd = '';
21555 var pm = this.trigger.child('div/div');
21556 pm.removeClass(this.meterClass);
21557 pm.addClass('roo-password-meter-grey');
21560 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21563 this.inputEl().dom.type='password';
21566 validateValue: function (value)
21569 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21572 if (value.length == 0) {
21573 if (this.allowBlank) {
21574 this.clearInvalid();
21578 this.markInvalid(this.errors.PwdEmpty);
21579 this.errorMsg = this.errors.PwdEmpty;
21587 if ('[\x21-\x7e]*'.match(value)) {
21588 this.markInvalid(this.errors.PwdBadChar);
21589 this.errorMsg = this.errors.PwdBadChar;
21592 if (value.length < 6) {
21593 this.markInvalid(this.errors.PwdShort);
21594 this.errorMsg = this.errors.PwdShort;
21597 if (value.length > 16) {
21598 this.markInvalid(this.errors.PwdLong);
21599 this.errorMsg = this.errors.PwdLong;
21603 if (this.ClientSideStrongPassword(value)) {
21605 } else if (this.ClientSideMediumPassword(value)) {
21607 } else if (this.ClientSideWeakPassword(value)) {
21614 if (strength < 2) {
21615 //this.markInvalid(this.errors.TooWeak);
21616 this.errorMsg = this.errors.TooWeak;
21621 console.log('strength2: ' + strength);
21623 //var pm = this.trigger.child('div/div/div').dom;
21625 var pm = this.trigger.child('div/div');
21626 pm.removeClass(this.meterClass);
21627 pm.addClass(this.meterClass[strength]);
21629 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21631 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21633 this.errorMsg = '';
21637 CharacterSetChecks: function (type)
21640 this.fResult = false;
21643 isctype: function (character, type)
21646 case this.kCapitalLetter:
21647 if (character >= 'A' && character <= 'Z') {
21652 case this.kSmallLetter:
21653 if (character >= 'a' && character <= 'z') {
21659 if (character >= '0' && character <= '9') {
21664 case this.kPunctuation:
21665 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21676 IsLongEnough: function (pwd, size)
21678 return !(pwd == null || isNaN(size) || pwd.length < size);
21681 SpansEnoughCharacterSets: function (word, nb)
21683 if (!this.IsLongEnough(word, nb))
21688 var characterSetChecks = new Array(
21689 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21690 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21693 for (var index = 0; index < word.length; ++index) {
21694 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21695 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21696 characterSetChecks[nCharSet].fResult = true;
21703 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21704 if (characterSetChecks[nCharSet].fResult) {
21709 if (nCharSets < nb) {
21715 ClientSideStrongPassword: function (pwd)
21717 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21720 ClientSideMediumPassword: function (pwd)
21722 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21725 ClientSideWeakPassword: function (pwd)
21727 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21730 })//<script type="text/javascript">
21733 * Based Ext JS Library 1.1.1
21734 * Copyright(c) 2006-2007, Ext JS, LLC.
21740 * @class Roo.HtmlEditorCore
21741 * @extends Roo.Component
21742 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21744 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21747 Roo.HtmlEditorCore = function(config){
21750 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21755 * @event initialize
21756 * Fires when the editor is fully initialized (including the iframe)
21757 * @param {Roo.HtmlEditorCore} this
21762 * Fires when the editor is first receives the focus. Any insertion must wait
21763 * until after this event.
21764 * @param {Roo.HtmlEditorCore} this
21768 * @event beforesync
21769 * Fires before the textarea is updated with content from the editor iframe. Return false
21770 * to cancel the sync.
21771 * @param {Roo.HtmlEditorCore} this
21772 * @param {String} html
21776 * @event beforepush
21777 * Fires before the iframe editor is updated with content from the textarea. Return false
21778 * to cancel the push.
21779 * @param {Roo.HtmlEditorCore} this
21780 * @param {String} html
21785 * Fires when the textarea is updated with content from the editor iframe.
21786 * @param {Roo.HtmlEditorCore} this
21787 * @param {String} html
21792 * Fires when the iframe editor is updated with content from the textarea.
21793 * @param {Roo.HtmlEditorCore} this
21794 * @param {String} html
21799 * @event editorevent
21800 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21801 * @param {Roo.HtmlEditorCore} this
21807 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21809 // defaults : white / black...
21810 this.applyBlacklists();
21817 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21821 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21827 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21832 * @cfg {Number} height (in pixels)
21836 * @cfg {Number} width (in pixels)
21841 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21844 stylesheets: false,
21849 // private properties
21850 validationEvent : false,
21852 initialized : false,
21854 sourceEditMode : false,
21855 onFocus : Roo.emptyFn,
21857 hideMode:'offsets',
21861 // blacklist + whitelisted elements..
21868 * Protected method that will not generally be called directly. It
21869 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21870 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21872 getDocMarkup : function(){
21876 // inherit styels from page...??
21877 if (this.stylesheets === false) {
21879 Roo.get(document.head).select('style').each(function(node) {
21880 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21883 Roo.get(document.head).select('link').each(function(node) {
21884 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21887 } else if (!this.stylesheets.length) {
21889 st = '<style type="text/css">' +
21890 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21893 st = '<style type="text/css">' +
21898 st += '<style type="text/css">' +
21899 'IMG { cursor: pointer } ' +
21902 var cls = 'roo-htmleditor-body';
21904 if(this.bodyCls.length){
21905 cls += ' ' + this.bodyCls;
21908 return '<html><head>' + st +
21909 //<style type="text/css">' +
21910 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21912 ' </head><body class="' + cls + '"></body></html>';
21916 onRender : function(ct, position)
21919 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21920 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21923 this.el.dom.style.border = '0 none';
21924 this.el.dom.setAttribute('tabIndex', -1);
21925 this.el.addClass('x-hidden hide');
21929 if(Roo.isIE){ // fix IE 1px bogus margin
21930 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21934 this.frameId = Roo.id();
21938 var iframe = this.owner.wrap.createChild({
21940 cls: 'form-control', // bootstrap..
21942 name: this.frameId,
21943 frameBorder : 'no',
21944 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21949 this.iframe = iframe.dom;
21951 this.assignDocWin();
21953 this.doc.designMode = 'on';
21956 this.doc.write(this.getDocMarkup());
21960 var task = { // must defer to wait for browser to be ready
21962 //console.log("run task?" + this.doc.readyState);
21963 this.assignDocWin();
21964 if(this.doc.body || this.doc.readyState == 'complete'){
21966 this.doc.designMode="on";
21970 Roo.TaskMgr.stop(task);
21971 this.initEditor.defer(10, this);
21978 Roo.TaskMgr.start(task);
21983 onResize : function(w, h)
21985 Roo.log('resize: ' +w + ',' + h );
21986 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21990 if(typeof w == 'number'){
21992 this.iframe.style.width = w + 'px';
21994 if(typeof h == 'number'){
21996 this.iframe.style.height = h + 'px';
21998 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22005 * Toggles the editor between standard and source edit mode.
22006 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22008 toggleSourceEdit : function(sourceEditMode){
22010 this.sourceEditMode = sourceEditMode === true;
22012 if(this.sourceEditMode){
22014 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22017 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22018 //this.iframe.className = '';
22021 //this.setSize(this.owner.wrap.getSize());
22022 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22029 * Protected method that will not generally be called directly. If you need/want
22030 * custom HTML cleanup, this is the method you should override.
22031 * @param {String} html The HTML to be cleaned
22032 * return {String} The cleaned HTML
22034 cleanHtml : function(html){
22035 html = String(html);
22036 if(html.length > 5){
22037 if(Roo.isSafari){ // strip safari nonsense
22038 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22041 if(html == ' '){
22048 * HTML Editor -> Textarea
22049 * Protected method that will not generally be called directly. Syncs the contents
22050 * of the editor iframe with the textarea.
22052 syncValue : function(){
22053 if(this.initialized){
22054 var bd = (this.doc.body || this.doc.documentElement);
22055 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22056 var html = bd.innerHTML;
22058 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22059 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22061 html = '<div style="'+m[0]+'">' + html + '</div>';
22064 html = this.cleanHtml(html);
22065 // fix up the special chars.. normaly like back quotes in word...
22066 // however we do not want to do this with chinese..
22067 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22068 var cc = b.charCodeAt();
22070 (cc >= 0x4E00 && cc < 0xA000 ) ||
22071 (cc >= 0x3400 && cc < 0x4E00 ) ||
22072 (cc >= 0xf900 && cc < 0xfb00 )
22078 if(this.owner.fireEvent('beforesync', this, html) !== false){
22079 this.el.dom.value = html;
22080 this.owner.fireEvent('sync', this, html);
22086 * Protected method that will not generally be called directly. Pushes the value of the textarea
22087 * into the iframe editor.
22089 pushValue : function(){
22090 if(this.initialized){
22091 var v = this.el.dom.value.trim();
22093 // if(v.length < 1){
22097 if(this.owner.fireEvent('beforepush', this, v) !== false){
22098 var d = (this.doc.body || this.doc.documentElement);
22100 this.cleanUpPaste();
22101 this.el.dom.value = d.innerHTML;
22102 this.owner.fireEvent('push', this, v);
22108 deferFocus : function(){
22109 this.focus.defer(10, this);
22113 focus : function(){
22114 if(this.win && !this.sourceEditMode){
22121 assignDocWin: function()
22123 var iframe = this.iframe;
22126 this.doc = iframe.contentWindow.document;
22127 this.win = iframe.contentWindow;
22129 // if (!Roo.get(this.frameId)) {
22132 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22133 // this.win = Roo.get(this.frameId).dom.contentWindow;
22135 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22139 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22140 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22145 initEditor : function(){
22146 //console.log("INIT EDITOR");
22147 this.assignDocWin();
22151 this.doc.designMode="on";
22153 this.doc.write(this.getDocMarkup());
22156 var dbody = (this.doc.body || this.doc.documentElement);
22157 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22158 // this copies styles from the containing element into thsi one..
22159 // not sure why we need all of this..
22160 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22162 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22163 //ss['background-attachment'] = 'fixed'; // w3c
22164 dbody.bgProperties = 'fixed'; // ie
22165 //Roo.DomHelper.applyStyles(dbody, ss);
22166 Roo.EventManager.on(this.doc, {
22167 //'mousedown': this.onEditorEvent,
22168 'mouseup': this.onEditorEvent,
22169 'dblclick': this.onEditorEvent,
22170 'click': this.onEditorEvent,
22171 'keyup': this.onEditorEvent,
22176 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22178 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22179 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22181 this.initialized = true;
22183 this.owner.fireEvent('initialize', this);
22188 onDestroy : function(){
22194 //for (var i =0; i < this.toolbars.length;i++) {
22195 // // fixme - ask toolbars for heights?
22196 // this.toolbars[i].onDestroy();
22199 //this.wrap.dom.innerHTML = '';
22200 //this.wrap.remove();
22205 onFirstFocus : function(){
22207 this.assignDocWin();
22210 this.activated = true;
22213 if(Roo.isGecko){ // prevent silly gecko errors
22215 var s = this.win.getSelection();
22216 if(!s.focusNode || s.focusNode.nodeType != 3){
22217 var r = s.getRangeAt(0);
22218 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22223 this.execCmd('useCSS', true);
22224 this.execCmd('styleWithCSS', false);
22227 this.owner.fireEvent('activate', this);
22231 adjustFont: function(btn){
22232 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22233 //if(Roo.isSafari){ // safari
22236 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22237 if(Roo.isSafari){ // safari
22238 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22239 v = (v < 10) ? 10 : v;
22240 v = (v > 48) ? 48 : v;
22241 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22246 v = Math.max(1, v+adjust);
22248 this.execCmd('FontSize', v );
22251 onEditorEvent : function(e)
22253 this.owner.fireEvent('editorevent', this, e);
22254 // this.updateToolbar();
22255 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22258 insertTag : function(tg)
22260 // could be a bit smarter... -> wrap the current selected tRoo..
22261 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22263 range = this.createRange(this.getSelection());
22264 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22265 wrappingNode.appendChild(range.extractContents());
22266 range.insertNode(wrappingNode);
22273 this.execCmd("formatblock", tg);
22277 insertText : function(txt)
22281 var range = this.createRange();
22282 range.deleteContents();
22283 //alert(Sender.getAttribute('label'));
22285 range.insertNode(this.doc.createTextNode(txt));
22291 * Executes a Midas editor command on the editor document and performs necessary focus and
22292 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22293 * @param {String} cmd The Midas command
22294 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22296 relayCmd : function(cmd, value){
22298 this.execCmd(cmd, value);
22299 this.owner.fireEvent('editorevent', this);
22300 //this.updateToolbar();
22301 this.owner.deferFocus();
22305 * Executes a Midas editor command directly on the editor document.
22306 * For visual commands, you should use {@link #relayCmd} instead.
22307 * <b>This should only be called after the editor is initialized.</b>
22308 * @param {String} cmd The Midas command
22309 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22311 execCmd : function(cmd, value){
22312 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22319 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22321 * @param {String} text | dom node..
22323 insertAtCursor : function(text)
22326 if(!this.activated){
22332 var r = this.doc.selection.createRange();
22343 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22347 // from jquery ui (MIT licenced)
22349 var win = this.win;
22351 if (win.getSelection && win.getSelection().getRangeAt) {
22352 range = win.getSelection().getRangeAt(0);
22353 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22354 range.insertNode(node);
22355 } else if (win.document.selection && win.document.selection.createRange) {
22356 // no firefox support
22357 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22358 win.document.selection.createRange().pasteHTML(txt);
22360 // no firefox support
22361 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22362 this.execCmd('InsertHTML', txt);
22371 mozKeyPress : function(e){
22373 var c = e.getCharCode(), cmd;
22376 c = String.fromCharCode(c).toLowerCase();
22390 this.cleanUpPaste.defer(100, this);
22398 e.preventDefault();
22406 fixKeys : function(){ // load time branching for fastest keydown performance
22408 return function(e){
22409 var k = e.getKey(), r;
22412 r = this.doc.selection.createRange();
22415 r.pasteHTML('    ');
22422 r = this.doc.selection.createRange();
22424 var target = r.parentElement();
22425 if(!target || target.tagName.toLowerCase() != 'li'){
22427 r.pasteHTML('<br />');
22433 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22434 this.cleanUpPaste.defer(100, this);
22440 }else if(Roo.isOpera){
22441 return function(e){
22442 var k = e.getKey();
22446 this.execCmd('InsertHTML','    ');
22449 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22450 this.cleanUpPaste.defer(100, this);
22455 }else if(Roo.isSafari){
22456 return function(e){
22457 var k = e.getKey();
22461 this.execCmd('InsertText','\t');
22465 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22466 this.cleanUpPaste.defer(100, this);
22474 getAllAncestors: function()
22476 var p = this.getSelectedNode();
22479 a.push(p); // push blank onto stack..
22480 p = this.getParentElement();
22484 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22488 a.push(this.doc.body);
22492 lastSelNode : false,
22495 getSelection : function()
22497 this.assignDocWin();
22498 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22501 getSelectedNode: function()
22503 // this may only work on Gecko!!!
22505 // should we cache this!!!!
22510 var range = this.createRange(this.getSelection()).cloneRange();
22513 var parent = range.parentElement();
22515 var testRange = range.duplicate();
22516 testRange.moveToElementText(parent);
22517 if (testRange.inRange(range)) {
22520 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22523 parent = parent.parentElement;
22528 // is ancestor a text element.
22529 var ac = range.commonAncestorContainer;
22530 if (ac.nodeType == 3) {
22531 ac = ac.parentNode;
22534 var ar = ac.childNodes;
22537 var other_nodes = [];
22538 var has_other_nodes = false;
22539 for (var i=0;i<ar.length;i++) {
22540 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22543 // fullly contained node.
22545 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22550 // probably selected..
22551 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22552 other_nodes.push(ar[i]);
22556 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22561 has_other_nodes = true;
22563 if (!nodes.length && other_nodes.length) {
22564 nodes= other_nodes;
22566 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22572 createRange: function(sel)
22574 // this has strange effects when using with
22575 // top toolbar - not sure if it's a great idea.
22576 //this.editor.contentWindow.focus();
22577 if (typeof sel != "undefined") {
22579 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22581 return this.doc.createRange();
22584 return this.doc.createRange();
22587 getParentElement: function()
22590 this.assignDocWin();
22591 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22593 var range = this.createRange(sel);
22596 var p = range.commonAncestorContainer;
22597 while (p.nodeType == 3) { // text node
22608 * Range intersection.. the hard stuff...
22612 * [ -- selected range --- ]
22616 * if end is before start or hits it. fail.
22617 * if start is after end or hits it fail.
22619 * if either hits (but other is outside. - then it's not
22625 // @see http://www.thismuchiknow.co.uk/?p=64.
22626 rangeIntersectsNode : function(range, node)
22628 var nodeRange = node.ownerDocument.createRange();
22630 nodeRange.selectNode(node);
22632 nodeRange.selectNodeContents(node);
22635 var rangeStartRange = range.cloneRange();
22636 rangeStartRange.collapse(true);
22638 var rangeEndRange = range.cloneRange();
22639 rangeEndRange.collapse(false);
22641 var nodeStartRange = nodeRange.cloneRange();
22642 nodeStartRange.collapse(true);
22644 var nodeEndRange = nodeRange.cloneRange();
22645 nodeEndRange.collapse(false);
22647 return rangeStartRange.compareBoundaryPoints(
22648 Range.START_TO_START, nodeEndRange) == -1 &&
22649 rangeEndRange.compareBoundaryPoints(
22650 Range.START_TO_START, nodeStartRange) == 1;
22654 rangeCompareNode : function(range, node)
22656 var nodeRange = node.ownerDocument.createRange();
22658 nodeRange.selectNode(node);
22660 nodeRange.selectNodeContents(node);
22664 range.collapse(true);
22666 nodeRange.collapse(true);
22668 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22669 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22671 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22673 var nodeIsBefore = ss == 1;
22674 var nodeIsAfter = ee == -1;
22676 if (nodeIsBefore && nodeIsAfter) {
22679 if (!nodeIsBefore && nodeIsAfter) {
22680 return 1; //right trailed.
22683 if (nodeIsBefore && !nodeIsAfter) {
22684 return 2; // left trailed.
22690 // private? - in a new class?
22691 cleanUpPaste : function()
22693 // cleans up the whole document..
22694 Roo.log('cleanuppaste');
22696 this.cleanUpChildren(this.doc.body);
22697 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22698 if (clean != this.doc.body.innerHTML) {
22699 this.doc.body.innerHTML = clean;
22704 cleanWordChars : function(input) {// change the chars to hex code
22705 var he = Roo.HtmlEditorCore;
22707 var output = input;
22708 Roo.each(he.swapCodes, function(sw) {
22709 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22711 output = output.replace(swapper, sw[1]);
22718 cleanUpChildren : function (n)
22720 if (!n.childNodes.length) {
22723 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22724 this.cleanUpChild(n.childNodes[i]);
22731 cleanUpChild : function (node)
22734 //console.log(node);
22735 if (node.nodeName == "#text") {
22736 // clean up silly Windows -- stuff?
22739 if (node.nodeName == "#comment") {
22740 node.parentNode.removeChild(node);
22741 // clean up silly Windows -- stuff?
22744 var lcname = node.tagName.toLowerCase();
22745 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22746 // whitelist of tags..
22748 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22750 node.parentNode.removeChild(node);
22755 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22757 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22758 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22760 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22761 // remove_keep_children = true;
22764 if (remove_keep_children) {
22765 this.cleanUpChildren(node);
22766 // inserts everything just before this node...
22767 while (node.childNodes.length) {
22768 var cn = node.childNodes[0];
22769 node.removeChild(cn);
22770 node.parentNode.insertBefore(cn, node);
22772 node.parentNode.removeChild(node);
22776 if (!node.attributes || !node.attributes.length) {
22777 this.cleanUpChildren(node);
22781 function cleanAttr(n,v)
22784 if (v.match(/^\./) || v.match(/^\//)) {
22787 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22790 if (v.match(/^#/)) {
22793 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22794 node.removeAttribute(n);
22798 var cwhite = this.cwhite;
22799 var cblack = this.cblack;
22801 function cleanStyle(n,v)
22803 if (v.match(/expression/)) { //XSS?? should we even bother..
22804 node.removeAttribute(n);
22808 var parts = v.split(/;/);
22811 Roo.each(parts, function(p) {
22812 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22816 var l = p.split(':').shift().replace(/\s+/g,'');
22817 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22819 if ( cwhite.length && cblack.indexOf(l) > -1) {
22820 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22821 //node.removeAttribute(n);
22825 // only allow 'c whitelisted system attributes'
22826 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22827 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22828 //node.removeAttribute(n);
22838 if (clean.length) {
22839 node.setAttribute(n, clean.join(';'));
22841 node.removeAttribute(n);
22847 for (var i = node.attributes.length-1; i > -1 ; i--) {
22848 var a = node.attributes[i];
22851 if (a.name.toLowerCase().substr(0,2)=='on') {
22852 node.removeAttribute(a.name);
22855 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22856 node.removeAttribute(a.name);
22859 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22860 cleanAttr(a.name,a.value); // fixme..
22863 if (a.name == 'style') {
22864 cleanStyle(a.name,a.value);
22867 /// clean up MS crap..
22868 // tecnically this should be a list of valid class'es..
22871 if (a.name == 'class') {
22872 if (a.value.match(/^Mso/)) {
22873 node.className = '';
22876 if (a.value.match(/^body$/)) {
22877 node.className = '';
22888 this.cleanUpChildren(node);
22894 * Clean up MS wordisms...
22896 cleanWord : function(node)
22901 this.cleanWord(this.doc.body);
22904 if (node.nodeName == "#text") {
22905 // clean up silly Windows -- stuff?
22908 if (node.nodeName == "#comment") {
22909 node.parentNode.removeChild(node);
22910 // clean up silly Windows -- stuff?
22914 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22915 node.parentNode.removeChild(node);
22919 // remove - but keep children..
22920 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22921 while (node.childNodes.length) {
22922 var cn = node.childNodes[0];
22923 node.removeChild(cn);
22924 node.parentNode.insertBefore(cn, node);
22926 node.parentNode.removeChild(node);
22927 this.iterateChildren(node, this.cleanWord);
22931 if (node.className.length) {
22933 var cn = node.className.split(/\W+/);
22935 Roo.each(cn, function(cls) {
22936 if (cls.match(/Mso[a-zA-Z]+/)) {
22941 node.className = cna.length ? cna.join(' ') : '';
22943 node.removeAttribute("class");
22947 if (node.hasAttribute("lang")) {
22948 node.removeAttribute("lang");
22951 if (node.hasAttribute("style")) {
22953 var styles = node.getAttribute("style").split(";");
22955 Roo.each(styles, function(s) {
22956 if (!s.match(/:/)) {
22959 var kv = s.split(":");
22960 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22963 // what ever is left... we allow.
22966 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22967 if (!nstyle.length) {
22968 node.removeAttribute('style');
22971 this.iterateChildren(node, this.cleanWord);
22977 * iterateChildren of a Node, calling fn each time, using this as the scole..
22978 * @param {DomNode} node node to iterate children of.
22979 * @param {Function} fn method of this class to call on each item.
22981 iterateChildren : function(node, fn)
22983 if (!node.childNodes.length) {
22986 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22987 fn.call(this, node.childNodes[i])
22993 * cleanTableWidths.
22995 * Quite often pasting from word etc.. results in tables with column and widths.
22996 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22999 cleanTableWidths : function(node)
23004 this.cleanTableWidths(this.doc.body);
23009 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23012 Roo.log(node.tagName);
23013 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23014 this.iterateChildren(node, this.cleanTableWidths);
23017 if (node.hasAttribute('width')) {
23018 node.removeAttribute('width');
23022 if (node.hasAttribute("style")) {
23025 var styles = node.getAttribute("style").split(";");
23027 Roo.each(styles, function(s) {
23028 if (!s.match(/:/)) {
23031 var kv = s.split(":");
23032 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23035 // what ever is left... we allow.
23038 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23039 if (!nstyle.length) {
23040 node.removeAttribute('style');
23044 this.iterateChildren(node, this.cleanTableWidths);
23052 domToHTML : function(currentElement, depth, nopadtext) {
23054 depth = depth || 0;
23055 nopadtext = nopadtext || false;
23057 if (!currentElement) {
23058 return this.domToHTML(this.doc.body);
23061 //Roo.log(currentElement);
23063 var allText = false;
23064 var nodeName = currentElement.nodeName;
23065 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23067 if (nodeName == '#text') {
23069 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23074 if (nodeName != 'BODY') {
23077 // Prints the node tagName, such as <A>, <IMG>, etc
23080 for(i = 0; i < currentElement.attributes.length;i++) {
23082 var aname = currentElement.attributes.item(i).name;
23083 if (!currentElement.attributes.item(i).value.length) {
23086 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23089 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23098 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23101 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23106 // Traverse the tree
23108 var currentElementChild = currentElement.childNodes.item(i);
23109 var allText = true;
23110 var innerHTML = '';
23112 while (currentElementChild) {
23113 // Formatting code (indent the tree so it looks nice on the screen)
23114 var nopad = nopadtext;
23115 if (lastnode == 'SPAN') {
23119 if (currentElementChild.nodeName == '#text') {
23120 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23121 toadd = nopadtext ? toadd : toadd.trim();
23122 if (!nopad && toadd.length > 80) {
23123 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23125 innerHTML += toadd;
23128 currentElementChild = currentElement.childNodes.item(i);
23134 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23136 // Recursively traverse the tree structure of the child node
23137 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23138 lastnode = currentElementChild.nodeName;
23140 currentElementChild=currentElement.childNodes.item(i);
23146 // The remaining code is mostly for formatting the tree
23147 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23152 ret+= "</"+tagName+">";
23158 applyBlacklists : function()
23160 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23161 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23165 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23166 if (b.indexOf(tag) > -1) {
23169 this.white.push(tag);
23173 Roo.each(w, function(tag) {
23174 if (b.indexOf(tag) > -1) {
23177 if (this.white.indexOf(tag) > -1) {
23180 this.white.push(tag);
23185 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23186 if (w.indexOf(tag) > -1) {
23189 this.black.push(tag);
23193 Roo.each(b, function(tag) {
23194 if (w.indexOf(tag) > -1) {
23197 if (this.black.indexOf(tag) > -1) {
23200 this.black.push(tag);
23205 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23206 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23210 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23211 if (b.indexOf(tag) > -1) {
23214 this.cwhite.push(tag);
23218 Roo.each(w, function(tag) {
23219 if (b.indexOf(tag) > -1) {
23222 if (this.cwhite.indexOf(tag) > -1) {
23225 this.cwhite.push(tag);
23230 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23231 if (w.indexOf(tag) > -1) {
23234 this.cblack.push(tag);
23238 Roo.each(b, function(tag) {
23239 if (w.indexOf(tag) > -1) {
23242 if (this.cblack.indexOf(tag) > -1) {
23245 this.cblack.push(tag);
23250 setStylesheets : function(stylesheets)
23252 if(typeof(stylesheets) == 'string'){
23253 Roo.get(this.iframe.contentDocument.head).createChild({
23255 rel : 'stylesheet',
23264 Roo.each(stylesheets, function(s) {
23269 Roo.get(_this.iframe.contentDocument.head).createChild({
23271 rel : 'stylesheet',
23280 removeStylesheets : function()
23284 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23289 setStyle : function(style)
23291 Roo.get(this.iframe.contentDocument.head).createChild({
23300 // hide stuff that is not compatible
23314 * @event specialkey
23318 * @cfg {String} fieldClass @hide
23321 * @cfg {String} focusClass @hide
23324 * @cfg {String} autoCreate @hide
23327 * @cfg {String} inputType @hide
23330 * @cfg {String} invalidClass @hide
23333 * @cfg {String} invalidText @hide
23336 * @cfg {String} msgFx @hide
23339 * @cfg {String} validateOnBlur @hide
23343 Roo.HtmlEditorCore.white = [
23344 'area', 'br', 'img', 'input', 'hr', 'wbr',
23346 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23347 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23348 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23349 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23350 'table', 'ul', 'xmp',
23352 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23355 'dir', 'menu', 'ol', 'ul', 'dl',
23361 Roo.HtmlEditorCore.black = [
23362 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23364 'base', 'basefont', 'bgsound', 'blink', 'body',
23365 'frame', 'frameset', 'head', 'html', 'ilayer',
23366 'iframe', 'layer', 'link', 'meta', 'object',
23367 'script', 'style' ,'title', 'xml' // clean later..
23369 Roo.HtmlEditorCore.clean = [
23370 'script', 'style', 'title', 'xml'
23372 Roo.HtmlEditorCore.remove = [
23377 Roo.HtmlEditorCore.ablack = [
23381 Roo.HtmlEditorCore.aclean = [
23382 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23386 Roo.HtmlEditorCore.pwhite= [
23387 'http', 'https', 'mailto'
23390 // white listed style attributes.
23391 Roo.HtmlEditorCore.cwhite= [
23392 // 'text-align', /// default is to allow most things..
23398 // black listed style attributes.
23399 Roo.HtmlEditorCore.cblack= [
23400 // 'font-size' -- this can be set by the project
23404 Roo.HtmlEditorCore.swapCodes =[
23423 * @class Roo.bootstrap.HtmlEditor
23424 * @extends Roo.bootstrap.TextArea
23425 * Bootstrap HtmlEditor class
23428 * Create a new HtmlEditor
23429 * @param {Object} config The config object
23432 Roo.bootstrap.HtmlEditor = function(config){
23433 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23434 if (!this.toolbars) {
23435 this.toolbars = [];
23438 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23441 * @event initialize
23442 * Fires when the editor is fully initialized (including the iframe)
23443 * @param {HtmlEditor} this
23448 * Fires when the editor is first receives the focus. Any insertion must wait
23449 * until after this event.
23450 * @param {HtmlEditor} this
23454 * @event beforesync
23455 * Fires before the textarea is updated with content from the editor iframe. Return false
23456 * to cancel the sync.
23457 * @param {HtmlEditor} this
23458 * @param {String} html
23462 * @event beforepush
23463 * Fires before the iframe editor is updated with content from the textarea. Return false
23464 * to cancel the push.
23465 * @param {HtmlEditor} this
23466 * @param {String} html
23471 * Fires when the textarea is updated with content from the editor iframe.
23472 * @param {HtmlEditor} this
23473 * @param {String} html
23478 * Fires when the iframe editor is updated with content from the textarea.
23479 * @param {HtmlEditor} this
23480 * @param {String} html
23484 * @event editmodechange
23485 * Fires when the editor switches edit modes
23486 * @param {HtmlEditor} this
23487 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23489 editmodechange: true,
23491 * @event editorevent
23492 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23493 * @param {HtmlEditor} this
23497 * @event firstfocus
23498 * Fires when on first focus - needed by toolbars..
23499 * @param {HtmlEditor} this
23504 * Auto save the htmlEditor value as a file into Events
23505 * @param {HtmlEditor} this
23509 * @event savedpreview
23510 * preview the saved version of htmlEditor
23511 * @param {HtmlEditor} this
23518 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23522 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23527 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23532 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23537 * @cfg {Number} height (in pixels)
23541 * @cfg {Number} width (in pixels)
23546 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23549 stylesheets: false,
23554 // private properties
23555 validationEvent : false,
23557 initialized : false,
23560 onFocus : Roo.emptyFn,
23562 hideMode:'offsets',
23564 tbContainer : false,
23568 toolbarContainer :function() {
23569 return this.wrap.select('.x-html-editor-tb',true).first();
23573 * Protected method that will not generally be called directly. It
23574 * is called when the editor creates its toolbar. Override this method if you need to
23575 * add custom toolbar buttons.
23576 * @param {HtmlEditor} editor
23578 createToolbar : function(){
23579 Roo.log('renewing');
23580 Roo.log("create toolbars");
23582 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23583 this.toolbars[0].render(this.toolbarContainer());
23587 // if (!editor.toolbars || !editor.toolbars.length) {
23588 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23591 // for (var i =0 ; i < editor.toolbars.length;i++) {
23592 // editor.toolbars[i] = Roo.factory(
23593 // typeof(editor.toolbars[i]) == 'string' ?
23594 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23595 // Roo.bootstrap.HtmlEditor);
23596 // editor.toolbars[i].init(editor);
23602 onRender : function(ct, position)
23604 // Roo.log("Call onRender: " + this.xtype);
23606 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23608 this.wrap = this.inputEl().wrap({
23609 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23612 this.editorcore.onRender(ct, position);
23614 if (this.resizable) {
23615 this.resizeEl = new Roo.Resizable(this.wrap, {
23619 minHeight : this.height,
23620 height: this.height,
23621 handles : this.resizable,
23624 resize : function(r, w, h) {
23625 _t.onResize(w,h); // -something
23631 this.createToolbar(this);
23634 if(!this.width && this.resizable){
23635 this.setSize(this.wrap.getSize());
23637 if (this.resizeEl) {
23638 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23639 // should trigger onReize..
23645 onResize : function(w, h)
23647 Roo.log('resize: ' +w + ',' + h );
23648 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23652 if(this.inputEl() ){
23653 if(typeof w == 'number'){
23654 var aw = w - this.wrap.getFrameWidth('lr');
23655 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23658 if(typeof h == 'number'){
23659 var tbh = -11; // fixme it needs to tool bar size!
23660 for (var i =0; i < this.toolbars.length;i++) {
23661 // fixme - ask toolbars for heights?
23662 tbh += this.toolbars[i].el.getHeight();
23663 //if (this.toolbars[i].footer) {
23664 // tbh += this.toolbars[i].footer.el.getHeight();
23672 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23673 ah -= 5; // knock a few pixes off for look..
23674 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23678 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23679 this.editorcore.onResize(ew,eh);
23684 * Toggles the editor between standard and source edit mode.
23685 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23687 toggleSourceEdit : function(sourceEditMode)
23689 this.editorcore.toggleSourceEdit(sourceEditMode);
23691 if(this.editorcore.sourceEditMode){
23692 Roo.log('editor - showing textarea');
23695 // Roo.log(this.syncValue());
23697 this.inputEl().removeClass(['hide', 'x-hidden']);
23698 this.inputEl().dom.removeAttribute('tabIndex');
23699 this.inputEl().focus();
23701 Roo.log('editor - hiding textarea');
23703 // Roo.log(this.pushValue());
23706 this.inputEl().addClass(['hide', 'x-hidden']);
23707 this.inputEl().dom.setAttribute('tabIndex', -1);
23708 //this.deferFocus();
23711 if(this.resizable){
23712 this.setSize(this.wrap.getSize());
23715 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23718 // private (for BoxComponent)
23719 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23721 // private (for BoxComponent)
23722 getResizeEl : function(){
23726 // private (for BoxComponent)
23727 getPositionEl : function(){
23732 initEvents : function(){
23733 this.originalValue = this.getValue();
23737 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23740 // markInvalid : Roo.emptyFn,
23742 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23745 // clearInvalid : Roo.emptyFn,
23747 setValue : function(v){
23748 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23749 this.editorcore.pushValue();
23754 deferFocus : function(){
23755 this.focus.defer(10, this);
23759 focus : function(){
23760 this.editorcore.focus();
23766 onDestroy : function(){
23772 for (var i =0; i < this.toolbars.length;i++) {
23773 // fixme - ask toolbars for heights?
23774 this.toolbars[i].onDestroy();
23777 this.wrap.dom.innerHTML = '';
23778 this.wrap.remove();
23783 onFirstFocus : function(){
23784 //Roo.log("onFirstFocus");
23785 this.editorcore.onFirstFocus();
23786 for (var i =0; i < this.toolbars.length;i++) {
23787 this.toolbars[i].onFirstFocus();
23793 syncValue : function()
23795 this.editorcore.syncValue();
23798 pushValue : function()
23800 this.editorcore.pushValue();
23804 // hide stuff that is not compatible
23818 * @event specialkey
23822 * @cfg {String} fieldClass @hide
23825 * @cfg {String} focusClass @hide
23828 * @cfg {String} autoCreate @hide
23831 * @cfg {String} inputType @hide
23834 * @cfg {String} invalidClass @hide
23837 * @cfg {String} invalidText @hide
23840 * @cfg {String} msgFx @hide
23843 * @cfg {String} validateOnBlur @hide
23852 Roo.namespace('Roo.bootstrap.htmleditor');
23854 * @class Roo.bootstrap.HtmlEditorToolbar1
23859 new Roo.bootstrap.HtmlEditor({
23862 new Roo.bootstrap.HtmlEditorToolbar1({
23863 disable : { fonts: 1 , format: 1, ..., ... , ...],
23869 * @cfg {Object} disable List of elements to disable..
23870 * @cfg {Array} btns List of additional buttons.
23874 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23877 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23880 Roo.apply(this, config);
23882 // default disabled, based on 'good practice'..
23883 this.disable = this.disable || {};
23884 Roo.applyIf(this.disable, {
23887 specialElements : true
23889 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23891 this.editor = config.editor;
23892 this.editorcore = config.editor.editorcore;
23894 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23896 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23897 // dont call parent... till later.
23899 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23904 editorcore : false,
23909 "h1","h2","h3","h4","h5","h6",
23911 "abbr", "acronym", "address", "cite", "samp", "var",
23915 onRender : function(ct, position)
23917 // Roo.log("Call onRender: " + this.xtype);
23919 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23921 this.el.dom.style.marginBottom = '0';
23923 var editorcore = this.editorcore;
23924 var editor= this.editor;
23927 var btn = function(id,cmd , toggle, handler, html){
23929 var event = toggle ? 'toggle' : 'click';
23934 xns: Roo.bootstrap,
23937 enableToggle:toggle !== false,
23939 pressed : toggle ? false : null,
23942 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23943 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23949 // var cb_box = function...
23954 xns: Roo.bootstrap,
23955 glyphicon : 'font',
23959 xns: Roo.bootstrap,
23963 Roo.each(this.formats, function(f) {
23964 style.menu.items.push({
23966 xns: Roo.bootstrap,
23967 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23972 editorcore.insertTag(this.tagname);
23979 children.push(style);
23981 btn('bold',false,true);
23982 btn('italic',false,true);
23983 btn('align-left', 'justifyleft',true);
23984 btn('align-center', 'justifycenter',true);
23985 btn('align-right' , 'justifyright',true);
23986 btn('link', false, false, function(btn) {
23987 //Roo.log("create link?");
23988 var url = prompt(this.createLinkText, this.defaultLinkValue);
23989 if(url && url != 'http:/'+'/'){
23990 this.editorcore.relayCmd('createlink', url);
23993 btn('list','insertunorderedlist',true);
23994 btn('pencil', false,true, function(btn){
23996 this.toggleSourceEdit(btn.pressed);
23999 if (this.editor.btns.length > 0) {
24000 for (var i = 0; i<this.editor.btns.length; i++) {
24001 children.push(this.editor.btns[i]);
24009 xns: Roo.bootstrap,
24014 xns: Roo.bootstrap,
24019 cog.menu.items.push({
24021 xns: Roo.bootstrap,
24022 html : Clean styles,
24027 editorcore.insertTag(this.tagname);
24036 this.xtype = 'NavSimplebar';
24038 for(var i=0;i< children.length;i++) {
24040 this.buttons.add(this.addxtypeChild(children[i]));
24044 editor.on('editorevent', this.updateToolbar, this);
24046 onBtnClick : function(id)
24048 this.editorcore.relayCmd(id);
24049 this.editorcore.focus();
24053 * Protected method that will not generally be called directly. It triggers
24054 * a toolbar update by reading the markup state of the current selection in the editor.
24056 updateToolbar: function(){
24058 if(!this.editorcore.activated){
24059 this.editor.onFirstFocus(); // is this neeed?
24063 var btns = this.buttons;
24064 var doc = this.editorcore.doc;
24065 btns.get('bold').setActive(doc.queryCommandState('bold'));
24066 btns.get('italic').setActive(doc.queryCommandState('italic'));
24067 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24069 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24070 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24071 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24073 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24074 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24077 var ans = this.editorcore.getAllAncestors();
24078 if (this.formatCombo) {
24081 var store = this.formatCombo.store;
24082 this.formatCombo.setValue("");
24083 for (var i =0; i < ans.length;i++) {
24084 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24086 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24094 // hides menus... - so this cant be on a menu...
24095 Roo.bootstrap.MenuMgr.hideAll();
24097 Roo.bootstrap.MenuMgr.hideAll();
24098 //this.editorsyncValue();
24100 onFirstFocus: function() {
24101 this.buttons.each(function(item){
24105 toggleSourceEdit : function(sourceEditMode){
24108 if(sourceEditMode){
24109 Roo.log("disabling buttons");
24110 this.buttons.each( function(item){
24111 if(item.cmd != 'pencil'){
24117 Roo.log("enabling buttons");
24118 if(this.editorcore.initialized){
24119 this.buttons.each( function(item){
24125 Roo.log("calling toggole on editor");
24126 // tell the editor that it's been pressed..
24127 this.editor.toggleSourceEdit(sourceEditMode);
24137 * @class Roo.bootstrap.Table.AbstractSelectionModel
24138 * @extends Roo.util.Observable
24139 * Abstract base class for grid SelectionModels. It provides the interface that should be
24140 * implemented by descendant classes. This class should not be directly instantiated.
24143 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24144 this.locked = false;
24145 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24149 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24150 /** @ignore Called by the grid automatically. Do not call directly. */
24151 init : function(grid){
24157 * Locks the selections.
24160 this.locked = true;
24164 * Unlocks the selections.
24166 unlock : function(){
24167 this.locked = false;
24171 * Returns true if the selections are locked.
24172 * @return {Boolean}
24174 isLocked : function(){
24175 return this.locked;
24179 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24180 * @class Roo.bootstrap.Table.RowSelectionModel
24181 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24182 * It supports multiple selections and keyboard selection/navigation.
24184 * @param {Object} config
24187 Roo.bootstrap.Table.RowSelectionModel = function(config){
24188 Roo.apply(this, config);
24189 this.selections = new Roo.util.MixedCollection(false, function(o){
24194 this.lastActive = false;
24198 * @event selectionchange
24199 * Fires when the selection changes
24200 * @param {SelectionModel} this
24202 "selectionchange" : true,
24204 * @event afterselectionchange
24205 * Fires after the selection changes (eg. by key press or clicking)
24206 * @param {SelectionModel} this
24208 "afterselectionchange" : true,
24210 * @event beforerowselect
24211 * Fires when a row is selected being selected, return false to cancel.
24212 * @param {SelectionModel} this
24213 * @param {Number} rowIndex The selected index
24214 * @param {Boolean} keepExisting False if other selections will be cleared
24216 "beforerowselect" : true,
24219 * Fires when a row is selected.
24220 * @param {SelectionModel} this
24221 * @param {Number} rowIndex The selected index
24222 * @param {Roo.data.Record} r The record
24224 "rowselect" : true,
24226 * @event rowdeselect
24227 * Fires when a row is deselected.
24228 * @param {SelectionModel} this
24229 * @param {Number} rowIndex The selected index
24231 "rowdeselect" : true
24233 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24234 this.locked = false;
24237 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24239 * @cfg {Boolean} singleSelect
24240 * True to allow selection of only one row at a time (defaults to false)
24242 singleSelect : false,
24245 initEvents : function()
24248 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24249 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24250 //}else{ // allow click to work like normal
24251 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24253 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24254 this.grid.on("rowclick", this.handleMouseDown, this);
24256 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24257 "up" : function(e){
24259 this.selectPrevious(e.shiftKey);
24260 }else if(this.last !== false && this.lastActive !== false){
24261 var last = this.last;
24262 this.selectRange(this.last, this.lastActive-1);
24263 this.grid.getView().focusRow(this.lastActive);
24264 if(last !== false){
24268 this.selectFirstRow();
24270 this.fireEvent("afterselectionchange", this);
24272 "down" : function(e){
24274 this.selectNext(e.shiftKey);
24275 }else if(this.last !== false && this.lastActive !== false){
24276 var last = this.last;
24277 this.selectRange(this.last, this.lastActive+1);
24278 this.grid.getView().focusRow(this.lastActive);
24279 if(last !== false){
24283 this.selectFirstRow();
24285 this.fireEvent("afterselectionchange", this);
24289 this.grid.store.on('load', function(){
24290 this.selections.clear();
24293 var view = this.grid.view;
24294 view.on("refresh", this.onRefresh, this);
24295 view.on("rowupdated", this.onRowUpdated, this);
24296 view.on("rowremoved", this.onRemove, this);
24301 onRefresh : function()
24303 var ds = this.grid.store, i, v = this.grid.view;
24304 var s = this.selections;
24305 s.each(function(r){
24306 if((i = ds.indexOfId(r.id)) != -1){
24315 onRemove : function(v, index, r){
24316 this.selections.remove(r);
24320 onRowUpdated : function(v, index, r){
24321 if(this.isSelected(r)){
24322 v.onRowSelect(index);
24328 * @param {Array} records The records to select
24329 * @param {Boolean} keepExisting (optional) True to keep existing selections
24331 selectRecords : function(records, keepExisting)
24334 this.clearSelections();
24336 var ds = this.grid.store;
24337 for(var i = 0, len = records.length; i < len; i++){
24338 this.selectRow(ds.indexOf(records[i]), true);
24343 * Gets the number of selected rows.
24346 getCount : function(){
24347 return this.selections.length;
24351 * Selects the first row in the grid.
24353 selectFirstRow : function(){
24358 * Select the last row.
24359 * @param {Boolean} keepExisting (optional) True to keep existing selections
24361 selectLastRow : function(keepExisting){
24362 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24363 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24367 * Selects the row immediately following the last selected row.
24368 * @param {Boolean} keepExisting (optional) True to keep existing selections
24370 selectNext : function(keepExisting)
24372 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24373 this.selectRow(this.last+1, keepExisting);
24374 this.grid.getView().focusRow(this.last);
24379 * Selects the row that precedes the last selected row.
24380 * @param {Boolean} keepExisting (optional) True to keep existing selections
24382 selectPrevious : function(keepExisting){
24384 this.selectRow(this.last-1, keepExisting);
24385 this.grid.getView().focusRow(this.last);
24390 * Returns the selected records
24391 * @return {Array} Array of selected records
24393 getSelections : function(){
24394 return [].concat(this.selections.items);
24398 * Returns the first selected record.
24401 getSelected : function(){
24402 return this.selections.itemAt(0);
24407 * Clears all selections.
24409 clearSelections : function(fast)
24415 var ds = this.grid.store;
24416 var s = this.selections;
24417 s.each(function(r){
24418 this.deselectRow(ds.indexOfId(r.id));
24422 this.selections.clear();
24429 * Selects all rows.
24431 selectAll : function(){
24435 this.selections.clear();
24436 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24437 this.selectRow(i, true);
24442 * Returns True if there is a selection.
24443 * @return {Boolean}
24445 hasSelection : function(){
24446 return this.selections.length > 0;
24450 * Returns True if the specified row is selected.
24451 * @param {Number/Record} record The record or index of the record to check
24452 * @return {Boolean}
24454 isSelected : function(index){
24455 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24456 return (r && this.selections.key(r.id) ? true : false);
24460 * Returns True if the specified record id is selected.
24461 * @param {String} id The id of record to check
24462 * @return {Boolean}
24464 isIdSelected : function(id){
24465 return (this.selections.key(id) ? true : false);
24470 handleMouseDBClick : function(e, t){
24474 handleMouseDown : function(e, t)
24476 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24477 if(this.isLocked() || rowIndex < 0 ){
24480 if(e.shiftKey && this.last !== false){
24481 var last = this.last;
24482 this.selectRange(last, rowIndex, e.ctrlKey);
24483 this.last = last; // reset the last
24487 var isSelected = this.isSelected(rowIndex);
24488 //Roo.log("select row:" + rowIndex);
24490 this.deselectRow(rowIndex);
24492 this.selectRow(rowIndex, true);
24496 if(e.button !== 0 && isSelected){
24497 alert('rowIndex 2: ' + rowIndex);
24498 view.focusRow(rowIndex);
24499 }else if(e.ctrlKey && isSelected){
24500 this.deselectRow(rowIndex);
24501 }else if(!isSelected){
24502 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24503 view.focusRow(rowIndex);
24507 this.fireEvent("afterselectionchange", this);
24510 handleDragableRowClick : function(grid, rowIndex, e)
24512 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24513 this.selectRow(rowIndex, false);
24514 grid.view.focusRow(rowIndex);
24515 this.fireEvent("afterselectionchange", this);
24520 * Selects multiple rows.
24521 * @param {Array} rows Array of the indexes of the row to select
24522 * @param {Boolean} keepExisting (optional) True to keep existing selections
24524 selectRows : function(rows, keepExisting){
24526 this.clearSelections();
24528 for(var i = 0, len = rows.length; i < len; i++){
24529 this.selectRow(rows[i], true);
24534 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24535 * @param {Number} startRow The index of the first row in the range
24536 * @param {Number} endRow The index of the last row in the range
24537 * @param {Boolean} keepExisting (optional) True to retain existing selections
24539 selectRange : function(startRow, endRow, keepExisting){
24544 this.clearSelections();
24546 if(startRow <= endRow){
24547 for(var i = startRow; i <= endRow; i++){
24548 this.selectRow(i, true);
24551 for(var i = startRow; i >= endRow; i--){
24552 this.selectRow(i, true);
24558 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24559 * @param {Number} startRow The index of the first row in the range
24560 * @param {Number} endRow The index of the last row in the range
24562 deselectRange : function(startRow, endRow, preventViewNotify){
24566 for(var i = startRow; i <= endRow; i++){
24567 this.deselectRow(i, preventViewNotify);
24573 * @param {Number} row The index of the row to select
24574 * @param {Boolean} keepExisting (optional) True to keep existing selections
24576 selectRow : function(index, keepExisting, preventViewNotify)
24578 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24581 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24582 if(!keepExisting || this.singleSelect){
24583 this.clearSelections();
24586 var r = this.grid.store.getAt(index);
24587 //console.log('selectRow - record id :' + r.id);
24589 this.selections.add(r);
24590 this.last = this.lastActive = index;
24591 if(!preventViewNotify){
24592 var proxy = new Roo.Element(
24593 this.grid.getRowDom(index)
24595 proxy.addClass('bg-info info');
24597 this.fireEvent("rowselect", this, index, r);
24598 this.fireEvent("selectionchange", this);
24604 * @param {Number} row The index of the row to deselect
24606 deselectRow : function(index, preventViewNotify)
24611 if(this.last == index){
24614 if(this.lastActive == index){
24615 this.lastActive = false;
24618 var r = this.grid.store.getAt(index);
24623 this.selections.remove(r);
24624 //.console.log('deselectRow - record id :' + r.id);
24625 if(!preventViewNotify){
24627 var proxy = new Roo.Element(
24628 this.grid.getRowDom(index)
24630 proxy.removeClass('bg-info info');
24632 this.fireEvent("rowdeselect", this, index);
24633 this.fireEvent("selectionchange", this);
24637 restoreLast : function(){
24639 this.last = this._last;
24644 acceptsNav : function(row, col, cm){
24645 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24649 onEditorKey : function(field, e){
24650 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24655 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24657 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24659 }else if(k == e.ENTER && !e.ctrlKey){
24663 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24665 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24667 }else if(k == e.ESC){
24671 g.startEditing(newCell[0], newCell[1]);
24677 * Ext JS Library 1.1.1
24678 * Copyright(c) 2006-2007, Ext JS, LLC.
24680 * Originally Released Under LGPL - original licence link has changed is not relivant.
24683 * <script type="text/javascript">
24687 * @class Roo.bootstrap.PagingToolbar
24688 * @extends Roo.bootstrap.NavSimplebar
24689 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24691 * Create a new PagingToolbar
24692 * @param {Object} config The config object
24693 * @param {Roo.data.Store} store
24695 Roo.bootstrap.PagingToolbar = function(config)
24697 // old args format still supported... - xtype is prefered..
24698 // created from xtype...
24700 this.ds = config.dataSource;
24702 if (config.store && !this.ds) {
24703 this.store= Roo.factory(config.store, Roo.data);
24704 this.ds = this.store;
24705 this.ds.xmodule = this.xmodule || false;
24708 this.toolbarItems = [];
24709 if (config.items) {
24710 this.toolbarItems = config.items;
24713 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24718 this.bind(this.ds);
24721 if (Roo.bootstrap.version == 4) {
24722 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24724 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24729 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24731 * @cfg {Roo.data.Store} dataSource
24732 * The underlying data store providing the paged data
24735 * @cfg {String/HTMLElement/Element} container
24736 * container The id or element that will contain the toolbar
24739 * @cfg {Boolean} displayInfo
24740 * True to display the displayMsg (defaults to false)
24743 * @cfg {Number} pageSize
24744 * The number of records to display per page (defaults to 20)
24748 * @cfg {String} displayMsg
24749 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24751 displayMsg : 'Displaying {0} - {1} of {2}',
24753 * @cfg {String} emptyMsg
24754 * The message to display when no records are found (defaults to "No data to display")
24756 emptyMsg : 'No data to display',
24758 * Customizable piece of the default paging text (defaults to "Page")
24761 beforePageText : "Page",
24763 * Customizable piece of the default paging text (defaults to "of %0")
24766 afterPageText : "of {0}",
24768 * Customizable piece of the default paging text (defaults to "First Page")
24771 firstText : "First Page",
24773 * Customizable piece of the default paging text (defaults to "Previous Page")
24776 prevText : "Previous Page",
24778 * Customizable piece of the default paging text (defaults to "Next Page")
24781 nextText : "Next Page",
24783 * Customizable piece of the default paging text (defaults to "Last Page")
24786 lastText : "Last Page",
24788 * Customizable piece of the default paging text (defaults to "Refresh")
24791 refreshText : "Refresh",
24795 onRender : function(ct, position)
24797 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24798 this.navgroup.parentId = this.id;
24799 this.navgroup.onRender(this.el, null);
24800 // add the buttons to the navgroup
24802 if(this.displayInfo){
24803 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24804 this.displayEl = this.el.select('.x-paging-info', true).first();
24805 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24806 // this.displayEl = navel.el.select('span',true).first();
24812 Roo.each(_this.buttons, function(e){ // this might need to use render????
24813 Roo.factory(e).render(_this.el);
24817 Roo.each(_this.toolbarItems, function(e) {
24818 _this.navgroup.addItem(e);
24822 this.first = this.navgroup.addItem({
24823 tooltip: this.firstText,
24824 cls: "prev btn-outline-secondary",
24825 html : ' <i class="fa fa-step-backward"></i>',
24827 preventDefault: true,
24828 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24831 this.prev = this.navgroup.addItem({
24832 tooltip: this.prevText,
24833 cls: "prev btn-outline-secondary",
24834 html : ' <i class="fa fa-backward"></i>',
24836 preventDefault: true,
24837 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24839 //this.addSeparator();
24842 var field = this.navgroup.addItem( {
24844 cls : 'x-paging-position btn-outline-secondary',
24846 html : this.beforePageText +
24847 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24848 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24851 this.field = field.el.select('input', true).first();
24852 this.field.on("keydown", this.onPagingKeydown, this);
24853 this.field.on("focus", function(){this.dom.select();});
24856 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24857 //this.field.setHeight(18);
24858 //this.addSeparator();
24859 this.next = this.navgroup.addItem({
24860 tooltip: this.nextText,
24861 cls: "next btn-outline-secondary",
24862 html : ' <i class="fa fa-forward"></i>',
24864 preventDefault: true,
24865 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24867 this.last = this.navgroup.addItem({
24868 tooltip: this.lastText,
24869 html : ' <i class="fa fa-step-forward"></i>',
24870 cls: "next btn-outline-secondary",
24872 preventDefault: true,
24873 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24875 //this.addSeparator();
24876 this.loading = this.navgroup.addItem({
24877 tooltip: this.refreshText,
24878 cls: "btn-outline-secondary",
24879 html : ' <i class="fa fa-refresh"></i>',
24880 preventDefault: true,
24881 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24887 updateInfo : function(){
24888 if(this.displayEl){
24889 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24890 var msg = count == 0 ?
24894 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24896 this.displayEl.update(msg);
24901 onLoad : function(ds, r, o)
24903 this.cursor = o.params.start ? o.params.start : 0;
24905 var d = this.getPageData(),
24910 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24911 this.field.dom.value = ap;
24912 this.first.setDisabled(ap == 1);
24913 this.prev.setDisabled(ap == 1);
24914 this.next.setDisabled(ap == ps);
24915 this.last.setDisabled(ap == ps);
24916 this.loading.enable();
24921 getPageData : function(){
24922 var total = this.ds.getTotalCount();
24925 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24926 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24931 onLoadError : function(){
24932 this.loading.enable();
24936 onPagingKeydown : function(e){
24937 var k = e.getKey();
24938 var d = this.getPageData();
24940 var v = this.field.dom.value, pageNum;
24941 if(!v || isNaN(pageNum = parseInt(v, 10))){
24942 this.field.dom.value = d.activePage;
24945 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24946 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24949 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))
24951 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24952 this.field.dom.value = pageNum;
24953 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24956 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24958 var v = this.field.dom.value, pageNum;
24959 var increment = (e.shiftKey) ? 10 : 1;
24960 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24963 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24964 this.field.dom.value = d.activePage;
24967 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24969 this.field.dom.value = parseInt(v, 10) + increment;
24970 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24971 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24978 beforeLoad : function(){
24980 this.loading.disable();
24985 onClick : function(which){
24994 ds.load({params:{start: 0, limit: this.pageSize}});
24997 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25000 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25003 var total = ds.getTotalCount();
25004 var extra = total % this.pageSize;
25005 var lastStart = extra ? (total - extra) : total-this.pageSize;
25006 ds.load({params:{start: lastStart, limit: this.pageSize}});
25009 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25015 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25016 * @param {Roo.data.Store} store The data store to unbind
25018 unbind : function(ds){
25019 ds.un("beforeload", this.beforeLoad, this);
25020 ds.un("load", this.onLoad, this);
25021 ds.un("loadexception", this.onLoadError, this);
25022 ds.un("remove", this.updateInfo, this);
25023 ds.un("add", this.updateInfo, this);
25024 this.ds = undefined;
25028 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25029 * @param {Roo.data.Store} store The data store to bind
25031 bind : function(ds){
25032 ds.on("beforeload", this.beforeLoad, this);
25033 ds.on("load", this.onLoad, this);
25034 ds.on("loadexception", this.onLoadError, this);
25035 ds.on("remove", this.updateInfo, this);
25036 ds.on("add", this.updateInfo, this);
25047 * @class Roo.bootstrap.MessageBar
25048 * @extends Roo.bootstrap.Component
25049 * Bootstrap MessageBar class
25050 * @cfg {String} html contents of the MessageBar
25051 * @cfg {String} weight (info | success | warning | danger) default info
25052 * @cfg {String} beforeClass insert the bar before the given class
25053 * @cfg {Boolean} closable (true | false) default false
25054 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25057 * Create a new Element
25058 * @param {Object} config The config object
25061 Roo.bootstrap.MessageBar = function(config){
25062 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25065 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25071 beforeClass: 'bootstrap-sticky-wrap',
25073 getAutoCreate : function(){
25077 cls: 'alert alert-dismissable alert-' + this.weight,
25082 html: this.html || ''
25088 cfg.cls += ' alert-messages-fixed';
25102 onRender : function(ct, position)
25104 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25107 var cfg = Roo.apply({}, this.getAutoCreate());
25111 cfg.cls += ' ' + this.cls;
25114 cfg.style = this.style;
25116 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25118 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25121 this.el.select('>button.close').on('click', this.hide, this);
25127 if (!this.rendered) {
25133 this.fireEvent('show', this);
25139 if (!this.rendered) {
25145 this.fireEvent('hide', this);
25148 update : function()
25150 // var e = this.el.dom.firstChild;
25152 // if(this.closable){
25153 // e = e.nextSibling;
25156 // e.data = this.html || '';
25158 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25174 * @class Roo.bootstrap.Graph
25175 * @extends Roo.bootstrap.Component
25176 * Bootstrap Graph class
25180 @cfg {String} graphtype bar | vbar | pie
25181 @cfg {number} g_x coodinator | centre x (pie)
25182 @cfg {number} g_y coodinator | centre y (pie)
25183 @cfg {number} g_r radius (pie)
25184 @cfg {number} g_height height of the chart (respected by all elements in the set)
25185 @cfg {number} g_width width of the chart (respected by all elements in the set)
25186 @cfg {Object} title The title of the chart
25189 -opts (object) options for the chart
25191 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25192 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25194 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.
25195 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25197 o stretch (boolean)
25199 -opts (object) options for the pie
25202 o startAngle (number)
25203 o endAngle (number)
25207 * Create a new Input
25208 * @param {Object} config The config object
25211 Roo.bootstrap.Graph = function(config){
25212 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25218 * The img click event for the img.
25219 * @param {Roo.EventObject} e
25225 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25236 //g_colors: this.colors,
25243 getAutoCreate : function(){
25254 onRender : function(ct,position){
25257 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25259 if (typeof(Raphael) == 'undefined') {
25260 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25264 this.raphael = Raphael(this.el.dom);
25266 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25267 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25268 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25269 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25271 r.text(160, 10, "Single Series Chart").attr(txtattr);
25272 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25273 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25274 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25276 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25277 r.barchart(330, 10, 300, 220, data1);
25278 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25279 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25282 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25283 // r.barchart(30, 30, 560, 250, xdata, {
25284 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25285 // axis : "0 0 1 1",
25286 // axisxlabels : xdata
25287 // //yvalues : cols,
25290 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25292 // this.load(null,xdata,{
25293 // axis : "0 0 1 1",
25294 // axisxlabels : xdata
25299 load : function(graphtype,xdata,opts)
25301 this.raphael.clear();
25303 graphtype = this.graphtype;
25308 var r = this.raphael,
25309 fin = function () {
25310 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25312 fout = function () {
25313 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25315 pfin = function() {
25316 this.sector.stop();
25317 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25320 this.label[0].stop();
25321 this.label[0].attr({ r: 7.5 });
25322 this.label[1].attr({ "font-weight": 800 });
25325 pfout = function() {
25326 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25329 this.label[0].animate({ r: 5 }, 500, "bounce");
25330 this.label[1].attr({ "font-weight": 400 });
25336 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25339 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25342 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25343 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25345 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25352 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25357 setTitle: function(o)
25362 initEvents: function() {
25365 this.el.on('click', this.onClick, this);
25369 onClick : function(e)
25371 Roo.log('img onclick');
25372 this.fireEvent('click', this, e);
25384 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25387 * @class Roo.bootstrap.dash.NumberBox
25388 * @extends Roo.bootstrap.Component
25389 * Bootstrap NumberBox class
25390 * @cfg {String} headline Box headline
25391 * @cfg {String} content Box content
25392 * @cfg {String} icon Box icon
25393 * @cfg {String} footer Footer text
25394 * @cfg {String} fhref Footer href
25397 * Create a new NumberBox
25398 * @param {Object} config The config object
25402 Roo.bootstrap.dash.NumberBox = function(config){
25403 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25407 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25416 getAutoCreate : function(){
25420 cls : 'small-box ',
25428 cls : 'roo-headline',
25429 html : this.headline
25433 cls : 'roo-content',
25434 html : this.content
25448 cls : 'ion ' + this.icon
25457 cls : 'small-box-footer',
25458 href : this.fhref || '#',
25462 cfg.cn.push(footer);
25469 onRender : function(ct,position){
25470 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25477 setHeadline: function (value)
25479 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25482 setFooter: function (value, href)
25484 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25487 this.el.select('a.small-box-footer',true).first().attr('href', href);
25492 setContent: function (value)
25494 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25497 initEvents: function()
25511 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25514 * @class Roo.bootstrap.dash.TabBox
25515 * @extends Roo.bootstrap.Component
25516 * Bootstrap TabBox class
25517 * @cfg {String} title Title of the TabBox
25518 * @cfg {String} icon Icon of the TabBox
25519 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25520 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25523 * Create a new TabBox
25524 * @param {Object} config The config object
25528 Roo.bootstrap.dash.TabBox = function(config){
25529 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25534 * When a pane is added
25535 * @param {Roo.bootstrap.dash.TabPane} pane
25539 * @event activatepane
25540 * When a pane is activated
25541 * @param {Roo.bootstrap.dash.TabPane} pane
25543 "activatepane" : true
25551 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25556 tabScrollable : false,
25558 getChildContainer : function()
25560 return this.el.select('.tab-content', true).first();
25563 getAutoCreate : function(){
25567 cls: 'pull-left header',
25575 cls: 'fa ' + this.icon
25581 cls: 'nav nav-tabs pull-right',
25587 if(this.tabScrollable){
25594 cls: 'nav nav-tabs pull-right',
25605 cls: 'nav-tabs-custom',
25610 cls: 'tab-content no-padding',
25618 initEvents : function()
25620 //Roo.log('add add pane handler');
25621 this.on('addpane', this.onAddPane, this);
25624 * Updates the box title
25625 * @param {String} html to set the title to.
25627 setTitle : function(value)
25629 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25631 onAddPane : function(pane)
25633 this.panes.push(pane);
25634 //Roo.log('addpane');
25636 // tabs are rendere left to right..
25637 if(!this.showtabs){
25641 var ctr = this.el.select('.nav-tabs', true).first();
25644 var existing = ctr.select('.nav-tab',true);
25645 var qty = existing.getCount();;
25648 var tab = ctr.createChild({
25650 cls : 'nav-tab' + (qty ? '' : ' active'),
25658 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25661 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25663 pane.el.addClass('active');
25668 onTabClick : function(ev,un,ob,pane)
25670 //Roo.log('tab - prev default');
25671 ev.preventDefault();
25674 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25675 pane.tab.addClass('active');
25676 //Roo.log(pane.title);
25677 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25678 // technically we should have a deactivate event.. but maybe add later.
25679 // and it should not de-activate the selected tab...
25680 this.fireEvent('activatepane', pane);
25681 pane.el.addClass('active');
25682 pane.fireEvent('activate');
25687 getActivePane : function()
25690 Roo.each(this.panes, function(p) {
25691 if(p.el.hasClass('active')){
25712 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25714 * @class Roo.bootstrap.TabPane
25715 * @extends Roo.bootstrap.Component
25716 * Bootstrap TabPane class
25717 * @cfg {Boolean} active (false | true) Default false
25718 * @cfg {String} title title of panel
25722 * Create a new TabPane
25723 * @param {Object} config The config object
25726 Roo.bootstrap.dash.TabPane = function(config){
25727 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25733 * When a pane is activated
25734 * @param {Roo.bootstrap.dash.TabPane} pane
25741 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25746 // the tabBox that this is attached to.
25749 getAutoCreate : function()
25757 cfg.cls += ' active';
25762 initEvents : function()
25764 //Roo.log('trigger add pane handler');
25765 this.parent().fireEvent('addpane', this)
25769 * Updates the tab title
25770 * @param {String} html to set the title to.
25772 setTitle: function(str)
25778 this.tab.select('a', true).first().dom.innerHTML = str;
25795 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25798 * @class Roo.bootstrap.menu.Menu
25799 * @extends Roo.bootstrap.Component
25800 * Bootstrap Menu class - container for Menu
25801 * @cfg {String} html Text of the menu
25802 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25803 * @cfg {String} icon Font awesome icon
25804 * @cfg {String} pos Menu align to (top | bottom) default bottom
25808 * Create a new Menu
25809 * @param {Object} config The config object
25813 Roo.bootstrap.menu.Menu = function(config){
25814 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25818 * @event beforeshow
25819 * Fires before this menu is displayed
25820 * @param {Roo.bootstrap.menu.Menu} this
25824 * @event beforehide
25825 * Fires before this menu is hidden
25826 * @param {Roo.bootstrap.menu.Menu} this
25831 * Fires after this menu is displayed
25832 * @param {Roo.bootstrap.menu.Menu} this
25837 * Fires after this menu is hidden
25838 * @param {Roo.bootstrap.menu.Menu} this
25843 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25844 * @param {Roo.bootstrap.menu.Menu} this
25845 * @param {Roo.EventObject} e
25852 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25856 weight : 'default',
25861 getChildContainer : function() {
25862 if(this.isSubMenu){
25866 return this.el.select('ul.dropdown-menu', true).first();
25869 getAutoCreate : function()
25874 cls : 'roo-menu-text',
25882 cls : 'fa ' + this.icon
25893 cls : 'dropdown-button btn btn-' + this.weight,
25898 cls : 'dropdown-toggle btn btn-' + this.weight,
25908 cls : 'dropdown-menu'
25914 if(this.pos == 'top'){
25915 cfg.cls += ' dropup';
25918 if(this.isSubMenu){
25921 cls : 'dropdown-menu'
25928 onRender : function(ct, position)
25930 this.isSubMenu = ct.hasClass('dropdown-submenu');
25932 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25935 initEvents : function()
25937 if(this.isSubMenu){
25941 this.hidden = true;
25943 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25944 this.triggerEl.on('click', this.onTriggerPress, this);
25946 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25947 this.buttonEl.on('click', this.onClick, this);
25953 if(this.isSubMenu){
25957 return this.el.select('ul.dropdown-menu', true).first();
25960 onClick : function(e)
25962 this.fireEvent("click", this, e);
25965 onTriggerPress : function(e)
25967 if (this.isVisible()) {
25974 isVisible : function(){
25975 return !this.hidden;
25980 this.fireEvent("beforeshow", this);
25982 this.hidden = false;
25983 this.el.addClass('open');
25985 Roo.get(document).on("mouseup", this.onMouseUp, this);
25987 this.fireEvent("show", this);
25994 this.fireEvent("beforehide", this);
25996 this.hidden = true;
25997 this.el.removeClass('open');
25999 Roo.get(document).un("mouseup", this.onMouseUp);
26001 this.fireEvent("hide", this);
26004 onMouseUp : function()
26018 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26021 * @class Roo.bootstrap.menu.Item
26022 * @extends Roo.bootstrap.Component
26023 * Bootstrap MenuItem class
26024 * @cfg {Boolean} submenu (true | false) default false
26025 * @cfg {String} html text of the item
26026 * @cfg {String} href the link
26027 * @cfg {Boolean} disable (true | false) default false
26028 * @cfg {Boolean} preventDefault (true | false) default true
26029 * @cfg {String} icon Font awesome icon
26030 * @cfg {String} pos Submenu align to (left | right) default right
26034 * Create a new Item
26035 * @param {Object} config The config object
26039 Roo.bootstrap.menu.Item = function(config){
26040 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26044 * Fires when the mouse is hovering over this menu
26045 * @param {Roo.bootstrap.menu.Item} this
26046 * @param {Roo.EventObject} e
26051 * Fires when the mouse exits this menu
26052 * @param {Roo.bootstrap.menu.Item} this
26053 * @param {Roo.EventObject} e
26059 * The raw click event for the entire grid.
26060 * @param {Roo.EventObject} e
26066 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26071 preventDefault: true,
26076 getAutoCreate : function()
26081 cls : 'roo-menu-item-text',
26089 cls : 'fa ' + this.icon
26098 href : this.href || '#',
26105 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26109 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26111 if(this.pos == 'left'){
26112 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26119 initEvents : function()
26121 this.el.on('mouseover', this.onMouseOver, this);
26122 this.el.on('mouseout', this.onMouseOut, this);
26124 this.el.select('a', true).first().on('click', this.onClick, this);
26128 onClick : function(e)
26130 if(this.preventDefault){
26131 e.preventDefault();
26134 this.fireEvent("click", this, e);
26137 onMouseOver : function(e)
26139 if(this.submenu && this.pos == 'left'){
26140 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26143 this.fireEvent("mouseover", this, e);
26146 onMouseOut : function(e)
26148 this.fireEvent("mouseout", this, e);
26160 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26163 * @class Roo.bootstrap.menu.Separator
26164 * @extends Roo.bootstrap.Component
26165 * Bootstrap Separator class
26168 * Create a new Separator
26169 * @param {Object} config The config object
26173 Roo.bootstrap.menu.Separator = function(config){
26174 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26177 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26179 getAutoCreate : function(){
26200 * @class Roo.bootstrap.Tooltip
26201 * Bootstrap Tooltip class
26202 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26203 * to determine which dom element triggers the tooltip.
26205 * It needs to add support for additional attributes like tooltip-position
26208 * Create a new Toolti
26209 * @param {Object} config The config object
26212 Roo.bootstrap.Tooltip = function(config){
26213 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26215 this.alignment = Roo.bootstrap.Tooltip.alignment;
26217 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26218 this.alignment = config.alignment;
26223 Roo.apply(Roo.bootstrap.Tooltip, {
26225 * @function init initialize tooltip monitoring.
26229 currentTip : false,
26230 currentRegion : false,
26236 Roo.get(document).on('mouseover', this.enter ,this);
26237 Roo.get(document).on('mouseout', this.leave, this);
26240 this.currentTip = new Roo.bootstrap.Tooltip();
26243 enter : function(ev)
26245 var dom = ev.getTarget();
26247 //Roo.log(['enter',dom]);
26248 var el = Roo.fly(dom);
26249 if (this.currentEl) {
26251 //Roo.log(this.currentEl);
26252 //Roo.log(this.currentEl.contains(dom));
26253 if (this.currentEl == el) {
26256 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26262 if (this.currentTip.el) {
26263 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26267 if(!el || el.dom == document){
26273 // you can not look for children, as if el is the body.. then everythign is the child..
26274 if (!el.attr('tooltip')) { //
26275 if (!el.select("[tooltip]").elements.length) {
26278 // is the mouse over this child...?
26279 bindEl = el.select("[tooltip]").first();
26280 var xy = ev.getXY();
26281 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26282 //Roo.log("not in region.");
26285 //Roo.log("child element over..");
26288 this.currentEl = bindEl;
26289 this.currentTip.bind(bindEl);
26290 this.currentRegion = Roo.lib.Region.getRegion(dom);
26291 this.currentTip.enter();
26294 leave : function(ev)
26296 var dom = ev.getTarget();
26297 //Roo.log(['leave',dom]);
26298 if (!this.currentEl) {
26303 if (dom != this.currentEl.dom) {
26306 var xy = ev.getXY();
26307 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26310 // only activate leave if mouse cursor is outside... bounding box..
26315 if (this.currentTip) {
26316 this.currentTip.leave();
26318 //Roo.log('clear currentEl');
26319 this.currentEl = false;
26324 'left' : ['r-l', [-2,0], 'right'],
26325 'right' : ['l-r', [2,0], 'left'],
26326 'bottom' : ['t-b', [0,2], 'top'],
26327 'top' : [ 'b-t', [0,-2], 'bottom']
26333 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26338 delay : null, // can be { show : 300 , hide: 500}
26342 hoverState : null, //???
26344 placement : 'bottom',
26348 getAutoCreate : function(){
26355 cls : 'tooltip-arrow'
26358 cls : 'tooltip-inner'
26365 bind : function(el)
26371 enter : function () {
26373 if (this.timeout != null) {
26374 clearTimeout(this.timeout);
26377 this.hoverState = 'in';
26378 //Roo.log("enter - show");
26379 if (!this.delay || !this.delay.show) {
26384 this.timeout = setTimeout(function () {
26385 if (_t.hoverState == 'in') {
26388 }, this.delay.show);
26392 clearTimeout(this.timeout);
26394 this.hoverState = 'out';
26395 if (!this.delay || !this.delay.hide) {
26401 this.timeout = setTimeout(function () {
26402 //Roo.log("leave - timeout");
26404 if (_t.hoverState == 'out') {
26406 Roo.bootstrap.Tooltip.currentEl = false;
26411 show : function (msg)
26414 this.render(document.body);
26417 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26419 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26421 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26423 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26425 var placement = typeof this.placement == 'function' ?
26426 this.placement.call(this, this.el, on_el) :
26429 var autoToken = /\s?auto?\s?/i;
26430 var autoPlace = autoToken.test(placement);
26432 placement = placement.replace(autoToken, '') || 'top';
26436 //this.el.setXY([0,0]);
26438 //this.el.dom.style.display='block';
26440 //this.el.appendTo(on_el);
26442 var p = this.getPosition();
26443 var box = this.el.getBox();
26449 var align = this.alignment[placement];
26451 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26453 if(placement == 'top' || placement == 'bottom'){
26455 placement = 'right';
26458 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26459 placement = 'left';
26462 var scroll = Roo.select('body', true).first().getScroll();
26464 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26468 align = this.alignment[placement];
26471 this.el.alignTo(this.bindEl, align[0],align[1]);
26472 //var arrow = this.el.select('.arrow',true).first();
26473 //arrow.set(align[2],
26475 this.el.addClass(placement);
26477 this.el.addClass('in fade');
26479 this.hoverState = null;
26481 if (this.el.hasClass('fade')) {
26492 //this.el.setXY([0,0]);
26493 this.el.removeClass('in');
26509 * @class Roo.bootstrap.LocationPicker
26510 * @extends Roo.bootstrap.Component
26511 * Bootstrap LocationPicker class
26512 * @cfg {Number} latitude Position when init default 0
26513 * @cfg {Number} longitude Position when init default 0
26514 * @cfg {Number} zoom default 15
26515 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26516 * @cfg {Boolean} mapTypeControl default false
26517 * @cfg {Boolean} disableDoubleClickZoom default false
26518 * @cfg {Boolean} scrollwheel default true
26519 * @cfg {Boolean} streetViewControl default false
26520 * @cfg {Number} radius default 0
26521 * @cfg {String} locationName
26522 * @cfg {Boolean} draggable default true
26523 * @cfg {Boolean} enableAutocomplete default false
26524 * @cfg {Boolean} enableReverseGeocode default true
26525 * @cfg {String} markerTitle
26528 * Create a new LocationPicker
26529 * @param {Object} config The config object
26533 Roo.bootstrap.LocationPicker = function(config){
26535 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26540 * Fires when the picker initialized.
26541 * @param {Roo.bootstrap.LocationPicker} this
26542 * @param {Google Location} location
26546 * @event positionchanged
26547 * Fires when the picker position changed.
26548 * @param {Roo.bootstrap.LocationPicker} this
26549 * @param {Google Location} location
26551 positionchanged : true,
26554 * Fires when the map resize.
26555 * @param {Roo.bootstrap.LocationPicker} this
26560 * Fires when the map show.
26561 * @param {Roo.bootstrap.LocationPicker} this
26566 * Fires when the map hide.
26567 * @param {Roo.bootstrap.LocationPicker} this
26572 * Fires when click the map.
26573 * @param {Roo.bootstrap.LocationPicker} this
26574 * @param {Map event} e
26578 * @event mapRightClick
26579 * Fires when right click the map.
26580 * @param {Roo.bootstrap.LocationPicker} this
26581 * @param {Map event} e
26583 mapRightClick : true,
26585 * @event markerClick
26586 * Fires when click the marker.
26587 * @param {Roo.bootstrap.LocationPicker} this
26588 * @param {Map event} e
26590 markerClick : true,
26592 * @event markerRightClick
26593 * Fires when right click the marker.
26594 * @param {Roo.bootstrap.LocationPicker} this
26595 * @param {Map event} e
26597 markerRightClick : true,
26599 * @event OverlayViewDraw
26600 * Fires when OverlayView Draw
26601 * @param {Roo.bootstrap.LocationPicker} this
26603 OverlayViewDraw : true,
26605 * @event OverlayViewOnAdd
26606 * Fires when OverlayView Draw
26607 * @param {Roo.bootstrap.LocationPicker} this
26609 OverlayViewOnAdd : true,
26611 * @event OverlayViewOnRemove
26612 * Fires when OverlayView Draw
26613 * @param {Roo.bootstrap.LocationPicker} this
26615 OverlayViewOnRemove : true,
26617 * @event OverlayViewShow
26618 * Fires when OverlayView Draw
26619 * @param {Roo.bootstrap.LocationPicker} this
26620 * @param {Pixel} cpx
26622 OverlayViewShow : true,
26624 * @event OverlayViewHide
26625 * Fires when OverlayView Draw
26626 * @param {Roo.bootstrap.LocationPicker} this
26628 OverlayViewHide : true,
26630 * @event loadexception
26631 * Fires when load google lib failed.
26632 * @param {Roo.bootstrap.LocationPicker} this
26634 loadexception : true
26639 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26641 gMapContext: false,
26647 mapTypeControl: false,
26648 disableDoubleClickZoom: false,
26650 streetViewControl: false,
26654 enableAutocomplete: false,
26655 enableReverseGeocode: true,
26658 getAutoCreate: function()
26663 cls: 'roo-location-picker'
26669 initEvents: function(ct, position)
26671 if(!this.el.getWidth() || this.isApplied()){
26675 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26680 initial: function()
26682 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26683 this.fireEvent('loadexception', this);
26687 if(!this.mapTypeId){
26688 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26691 this.gMapContext = this.GMapContext();
26693 this.initOverlayView();
26695 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26699 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26700 _this.setPosition(_this.gMapContext.marker.position);
26703 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26704 _this.fireEvent('mapClick', this, event);
26708 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26709 _this.fireEvent('mapRightClick', this, event);
26713 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26714 _this.fireEvent('markerClick', this, event);
26718 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26719 _this.fireEvent('markerRightClick', this, event);
26723 this.setPosition(this.gMapContext.location);
26725 this.fireEvent('initial', this, this.gMapContext.location);
26728 initOverlayView: function()
26732 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26736 _this.fireEvent('OverlayViewDraw', _this);
26741 _this.fireEvent('OverlayViewOnAdd', _this);
26744 onRemove: function()
26746 _this.fireEvent('OverlayViewOnRemove', _this);
26749 show: function(cpx)
26751 _this.fireEvent('OverlayViewShow', _this, cpx);
26756 _this.fireEvent('OverlayViewHide', _this);
26762 fromLatLngToContainerPixel: function(event)
26764 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26767 isApplied: function()
26769 return this.getGmapContext() == false ? false : true;
26772 getGmapContext: function()
26774 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26777 GMapContext: function()
26779 var position = new google.maps.LatLng(this.latitude, this.longitude);
26781 var _map = new google.maps.Map(this.el.dom, {
26784 mapTypeId: this.mapTypeId,
26785 mapTypeControl: this.mapTypeControl,
26786 disableDoubleClickZoom: this.disableDoubleClickZoom,
26787 scrollwheel: this.scrollwheel,
26788 streetViewControl: this.streetViewControl,
26789 locationName: this.locationName,
26790 draggable: this.draggable,
26791 enableAutocomplete: this.enableAutocomplete,
26792 enableReverseGeocode: this.enableReverseGeocode
26795 var _marker = new google.maps.Marker({
26796 position: position,
26798 title: this.markerTitle,
26799 draggable: this.draggable
26806 location: position,
26807 radius: this.radius,
26808 locationName: this.locationName,
26809 addressComponents: {
26810 formatted_address: null,
26811 addressLine1: null,
26812 addressLine2: null,
26814 streetNumber: null,
26818 stateOrProvince: null
26821 domContainer: this.el.dom,
26822 geodecoder: new google.maps.Geocoder()
26826 drawCircle: function(center, radius, options)
26828 if (this.gMapContext.circle != null) {
26829 this.gMapContext.circle.setMap(null);
26833 options = Roo.apply({}, options, {
26834 strokeColor: "#0000FF",
26835 strokeOpacity: .35,
26837 fillColor: "#0000FF",
26841 options.map = this.gMapContext.map;
26842 options.radius = radius;
26843 options.center = center;
26844 this.gMapContext.circle = new google.maps.Circle(options);
26845 return this.gMapContext.circle;
26851 setPosition: function(location)
26853 this.gMapContext.location = location;
26854 this.gMapContext.marker.setPosition(location);
26855 this.gMapContext.map.panTo(location);
26856 this.drawCircle(location, this.gMapContext.radius, {});
26860 if (this.gMapContext.settings.enableReverseGeocode) {
26861 this.gMapContext.geodecoder.geocode({
26862 latLng: this.gMapContext.location
26863 }, function(results, status) {
26865 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26866 _this.gMapContext.locationName = results[0].formatted_address;
26867 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26869 _this.fireEvent('positionchanged', this, location);
26876 this.fireEvent('positionchanged', this, location);
26881 google.maps.event.trigger(this.gMapContext.map, "resize");
26883 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26885 this.fireEvent('resize', this);
26888 setPositionByLatLng: function(latitude, longitude)
26890 this.setPosition(new google.maps.LatLng(latitude, longitude));
26893 getCurrentPosition: function()
26896 latitude: this.gMapContext.location.lat(),
26897 longitude: this.gMapContext.location.lng()
26901 getAddressName: function()
26903 return this.gMapContext.locationName;
26906 getAddressComponents: function()
26908 return this.gMapContext.addressComponents;
26911 address_component_from_google_geocode: function(address_components)
26915 for (var i = 0; i < address_components.length; i++) {
26916 var component = address_components[i];
26917 if (component.types.indexOf("postal_code") >= 0) {
26918 result.postalCode = component.short_name;
26919 } else if (component.types.indexOf("street_number") >= 0) {
26920 result.streetNumber = component.short_name;
26921 } else if (component.types.indexOf("route") >= 0) {
26922 result.streetName = component.short_name;
26923 } else if (component.types.indexOf("neighborhood") >= 0) {
26924 result.city = component.short_name;
26925 } else if (component.types.indexOf("locality") >= 0) {
26926 result.city = component.short_name;
26927 } else if (component.types.indexOf("sublocality") >= 0) {
26928 result.district = component.short_name;
26929 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26930 result.stateOrProvince = component.short_name;
26931 } else if (component.types.indexOf("country") >= 0) {
26932 result.country = component.short_name;
26936 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26937 result.addressLine2 = "";
26941 setZoomLevel: function(zoom)
26943 this.gMapContext.map.setZoom(zoom);
26956 this.fireEvent('show', this);
26967 this.fireEvent('hide', this);
26972 Roo.apply(Roo.bootstrap.LocationPicker, {
26974 OverlayView : function(map, options)
26976 options = options || {};
26990 * @class Roo.bootstrap.Alert
26991 * @extends Roo.bootstrap.Component
26992 * Bootstrap Alert class
26993 * @cfg {String} title The title of alert
26994 * @cfg {String} html The content of alert
26995 * @cfg {String} weight ( success | info | warning | danger )
26996 * @cfg {String} faicon font-awesomeicon
26999 * Create a new alert
27000 * @param {Object} config The config object
27004 Roo.bootstrap.Alert = function(config){
27005 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27009 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27016 getAutoCreate : function()
27025 cls : 'roo-alert-icon'
27030 cls : 'roo-alert-title',
27035 cls : 'roo-alert-text',
27042 cfg.cn[0].cls += ' fa ' + this.faicon;
27046 cfg.cls += ' alert-' + this.weight;
27052 initEvents: function()
27054 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27057 setTitle : function(str)
27059 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27062 setText : function(str)
27064 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27067 setWeight : function(weight)
27070 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27073 this.weight = weight;
27075 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27078 setIcon : function(icon)
27081 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27084 this.faicon = icon;
27086 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27107 * @class Roo.bootstrap.UploadCropbox
27108 * @extends Roo.bootstrap.Component
27109 * Bootstrap UploadCropbox class
27110 * @cfg {String} emptyText show when image has been loaded
27111 * @cfg {String} rotateNotify show when image too small to rotate
27112 * @cfg {Number} errorTimeout default 3000
27113 * @cfg {Number} minWidth default 300
27114 * @cfg {Number} minHeight default 300
27115 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27116 * @cfg {Boolean} isDocument (true|false) default false
27117 * @cfg {String} url action url
27118 * @cfg {String} paramName default 'imageUpload'
27119 * @cfg {String} method default POST
27120 * @cfg {Boolean} loadMask (true|false) default true
27121 * @cfg {Boolean} loadingText default 'Loading...'
27124 * Create a new UploadCropbox
27125 * @param {Object} config The config object
27128 Roo.bootstrap.UploadCropbox = function(config){
27129 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27133 * @event beforeselectfile
27134 * Fire before select file
27135 * @param {Roo.bootstrap.UploadCropbox} this
27137 "beforeselectfile" : true,
27140 * Fire after initEvent
27141 * @param {Roo.bootstrap.UploadCropbox} this
27146 * Fire after initEvent
27147 * @param {Roo.bootstrap.UploadCropbox} this
27148 * @param {String} data
27153 * Fire when preparing the file data
27154 * @param {Roo.bootstrap.UploadCropbox} this
27155 * @param {Object} file
27160 * Fire when get exception
27161 * @param {Roo.bootstrap.UploadCropbox} this
27162 * @param {XMLHttpRequest} xhr
27164 "exception" : true,
27166 * @event beforeloadcanvas
27167 * Fire before load the canvas
27168 * @param {Roo.bootstrap.UploadCropbox} this
27169 * @param {String} src
27171 "beforeloadcanvas" : true,
27174 * Fire when trash image
27175 * @param {Roo.bootstrap.UploadCropbox} this
27180 * Fire when download the image
27181 * @param {Roo.bootstrap.UploadCropbox} this
27185 * @event footerbuttonclick
27186 * Fire when footerbuttonclick
27187 * @param {Roo.bootstrap.UploadCropbox} this
27188 * @param {String} type
27190 "footerbuttonclick" : true,
27194 * @param {Roo.bootstrap.UploadCropbox} this
27199 * Fire when rotate the image
27200 * @param {Roo.bootstrap.UploadCropbox} this
27201 * @param {String} pos
27206 * Fire when inspect the file
27207 * @param {Roo.bootstrap.UploadCropbox} this
27208 * @param {Object} file
27213 * Fire when xhr upload the file
27214 * @param {Roo.bootstrap.UploadCropbox} this
27215 * @param {Object} data
27220 * Fire when arrange the file data
27221 * @param {Roo.bootstrap.UploadCropbox} this
27222 * @param {Object} formData
27227 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27230 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27232 emptyText : 'Click to upload image',
27233 rotateNotify : 'Image is too small to rotate',
27234 errorTimeout : 3000,
27248 cropType : 'image/jpeg',
27250 canvasLoaded : false,
27251 isDocument : false,
27253 paramName : 'imageUpload',
27255 loadingText : 'Loading...',
27258 getAutoCreate : function()
27262 cls : 'roo-upload-cropbox',
27266 cls : 'roo-upload-cropbox-selector',
27271 cls : 'roo-upload-cropbox-body',
27272 style : 'cursor:pointer',
27276 cls : 'roo-upload-cropbox-preview'
27280 cls : 'roo-upload-cropbox-thumb'
27284 cls : 'roo-upload-cropbox-empty-notify',
27285 html : this.emptyText
27289 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27290 html : this.rotateNotify
27296 cls : 'roo-upload-cropbox-footer',
27299 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27309 onRender : function(ct, position)
27311 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27313 if (this.buttons.length) {
27315 Roo.each(this.buttons, function(bb) {
27317 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27319 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27325 this.maskEl = this.el;
27329 initEvents : function()
27331 this.urlAPI = (window.createObjectURL && window) ||
27332 (window.URL && URL.revokeObjectURL && URL) ||
27333 (window.webkitURL && webkitURL);
27335 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27336 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27338 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27339 this.selectorEl.hide();
27341 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27342 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27344 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27345 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27346 this.thumbEl.hide();
27348 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27349 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27351 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27352 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27353 this.errorEl.hide();
27355 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27356 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27357 this.footerEl.hide();
27359 this.setThumbBoxSize();
27365 this.fireEvent('initial', this);
27372 window.addEventListener("resize", function() { _this.resize(); } );
27374 this.bodyEl.on('click', this.beforeSelectFile, this);
27377 this.bodyEl.on('touchstart', this.onTouchStart, this);
27378 this.bodyEl.on('touchmove', this.onTouchMove, this);
27379 this.bodyEl.on('touchend', this.onTouchEnd, this);
27383 this.bodyEl.on('mousedown', this.onMouseDown, this);
27384 this.bodyEl.on('mousemove', this.onMouseMove, this);
27385 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27386 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27387 Roo.get(document).on('mouseup', this.onMouseUp, this);
27390 this.selectorEl.on('change', this.onFileSelected, this);
27396 this.baseScale = 1;
27398 this.baseRotate = 1;
27399 this.dragable = false;
27400 this.pinching = false;
27403 this.cropData = false;
27404 this.notifyEl.dom.innerHTML = this.emptyText;
27406 this.selectorEl.dom.value = '';
27410 resize : function()
27412 if(this.fireEvent('resize', this) != false){
27413 this.setThumbBoxPosition();
27414 this.setCanvasPosition();
27418 onFooterButtonClick : function(e, el, o, type)
27421 case 'rotate-left' :
27422 this.onRotateLeft(e);
27424 case 'rotate-right' :
27425 this.onRotateRight(e);
27428 this.beforeSelectFile(e);
27443 this.fireEvent('footerbuttonclick', this, type);
27446 beforeSelectFile : function(e)
27448 e.preventDefault();
27450 if(this.fireEvent('beforeselectfile', this) != false){
27451 this.selectorEl.dom.click();
27455 onFileSelected : function(e)
27457 e.preventDefault();
27459 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27463 var file = this.selectorEl.dom.files[0];
27465 if(this.fireEvent('inspect', this, file) != false){
27466 this.prepare(file);
27471 trash : function(e)
27473 this.fireEvent('trash', this);
27476 download : function(e)
27478 this.fireEvent('download', this);
27481 loadCanvas : function(src)
27483 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27487 this.imageEl = document.createElement('img');
27491 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27493 this.imageEl.src = src;
27497 onLoadCanvas : function()
27499 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27500 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27502 this.bodyEl.un('click', this.beforeSelectFile, this);
27504 this.notifyEl.hide();
27505 this.thumbEl.show();
27506 this.footerEl.show();
27508 this.baseRotateLevel();
27510 if(this.isDocument){
27511 this.setThumbBoxSize();
27514 this.setThumbBoxPosition();
27516 this.baseScaleLevel();
27522 this.canvasLoaded = true;
27525 this.maskEl.unmask();
27530 setCanvasPosition : function()
27532 if(!this.canvasEl){
27536 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27537 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27539 this.previewEl.setLeft(pw);
27540 this.previewEl.setTop(ph);
27544 onMouseDown : function(e)
27548 this.dragable = true;
27549 this.pinching = false;
27551 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27552 this.dragable = false;
27556 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27557 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27561 onMouseMove : function(e)
27565 if(!this.canvasLoaded){
27569 if (!this.dragable){
27573 var minX = Math.ceil(this.thumbEl.getLeft(true));
27574 var minY = Math.ceil(this.thumbEl.getTop(true));
27576 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27577 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27579 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27580 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27582 x = x - this.mouseX;
27583 y = y - this.mouseY;
27585 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27586 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27588 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27589 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27591 this.previewEl.setLeft(bgX);
27592 this.previewEl.setTop(bgY);
27594 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27595 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27598 onMouseUp : function(e)
27602 this.dragable = false;
27605 onMouseWheel : function(e)
27609 this.startScale = this.scale;
27611 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27613 if(!this.zoomable()){
27614 this.scale = this.startScale;
27623 zoomable : function()
27625 var minScale = this.thumbEl.getWidth() / this.minWidth;
27627 if(this.minWidth < this.minHeight){
27628 minScale = this.thumbEl.getHeight() / this.minHeight;
27631 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27632 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27636 (this.rotate == 0 || this.rotate == 180) &&
27638 width > this.imageEl.OriginWidth ||
27639 height > this.imageEl.OriginHeight ||
27640 (width < this.minWidth && height < this.minHeight)
27648 (this.rotate == 90 || this.rotate == 270) &&
27650 width > this.imageEl.OriginWidth ||
27651 height > this.imageEl.OriginHeight ||
27652 (width < this.minHeight && height < this.minWidth)
27659 !this.isDocument &&
27660 (this.rotate == 0 || this.rotate == 180) &&
27662 width < this.minWidth ||
27663 width > this.imageEl.OriginWidth ||
27664 height < this.minHeight ||
27665 height > this.imageEl.OriginHeight
27672 !this.isDocument &&
27673 (this.rotate == 90 || this.rotate == 270) &&
27675 width < this.minHeight ||
27676 width > this.imageEl.OriginWidth ||
27677 height < this.minWidth ||
27678 height > this.imageEl.OriginHeight
27688 onRotateLeft : function(e)
27690 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27692 var minScale = this.thumbEl.getWidth() / this.minWidth;
27694 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27695 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27697 this.startScale = this.scale;
27699 while (this.getScaleLevel() < minScale){
27701 this.scale = this.scale + 1;
27703 if(!this.zoomable()){
27708 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27709 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27714 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27721 this.scale = this.startScale;
27723 this.onRotateFail();
27728 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27730 if(this.isDocument){
27731 this.setThumbBoxSize();
27732 this.setThumbBoxPosition();
27733 this.setCanvasPosition();
27738 this.fireEvent('rotate', this, 'left');
27742 onRotateRight : function(e)
27744 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27746 var minScale = this.thumbEl.getWidth() / this.minWidth;
27748 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27749 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27751 this.startScale = this.scale;
27753 while (this.getScaleLevel() < minScale){
27755 this.scale = this.scale + 1;
27757 if(!this.zoomable()){
27762 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27763 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27768 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27775 this.scale = this.startScale;
27777 this.onRotateFail();
27782 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27784 if(this.isDocument){
27785 this.setThumbBoxSize();
27786 this.setThumbBoxPosition();
27787 this.setCanvasPosition();
27792 this.fireEvent('rotate', this, 'right');
27795 onRotateFail : function()
27797 this.errorEl.show(true);
27801 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27806 this.previewEl.dom.innerHTML = '';
27808 var canvasEl = document.createElement("canvas");
27810 var contextEl = canvasEl.getContext("2d");
27812 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27813 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27814 var center = this.imageEl.OriginWidth / 2;
27816 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27817 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27818 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27819 center = this.imageEl.OriginHeight / 2;
27822 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27824 contextEl.translate(center, center);
27825 contextEl.rotate(this.rotate * Math.PI / 180);
27827 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27829 this.canvasEl = document.createElement("canvas");
27831 this.contextEl = this.canvasEl.getContext("2d");
27833 switch (this.rotate) {
27836 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27837 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27839 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27844 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27845 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27847 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27848 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);
27852 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27857 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27858 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27860 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27861 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);
27865 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);
27870 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27871 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27873 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27874 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27878 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);
27885 this.previewEl.appendChild(this.canvasEl);
27887 this.setCanvasPosition();
27892 if(!this.canvasLoaded){
27896 var imageCanvas = document.createElement("canvas");
27898 var imageContext = imageCanvas.getContext("2d");
27900 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27901 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27903 var center = imageCanvas.width / 2;
27905 imageContext.translate(center, center);
27907 imageContext.rotate(this.rotate * Math.PI / 180);
27909 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27911 var canvas = document.createElement("canvas");
27913 var context = canvas.getContext("2d");
27915 canvas.width = this.minWidth;
27916 canvas.height = this.minHeight;
27918 switch (this.rotate) {
27921 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27922 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27924 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27925 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27927 var targetWidth = this.minWidth - 2 * x;
27928 var targetHeight = this.minHeight - 2 * y;
27932 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27933 scale = targetWidth / width;
27936 if(x > 0 && y == 0){
27937 scale = targetHeight / height;
27940 if(x > 0 && y > 0){
27941 scale = targetWidth / width;
27943 if(width < height){
27944 scale = targetHeight / height;
27948 context.scale(scale, scale);
27950 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27951 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27953 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27954 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27956 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27961 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27962 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27964 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27965 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27967 var targetWidth = this.minWidth - 2 * x;
27968 var targetHeight = this.minHeight - 2 * y;
27972 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27973 scale = targetWidth / width;
27976 if(x > 0 && y == 0){
27977 scale = targetHeight / height;
27980 if(x > 0 && y > 0){
27981 scale = targetWidth / width;
27983 if(width < height){
27984 scale = targetHeight / height;
27988 context.scale(scale, scale);
27990 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27991 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27993 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27994 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27996 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27998 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28003 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28004 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28006 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28007 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28009 var targetWidth = this.minWidth - 2 * x;
28010 var targetHeight = this.minHeight - 2 * y;
28014 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28015 scale = targetWidth / width;
28018 if(x > 0 && y == 0){
28019 scale = targetHeight / height;
28022 if(x > 0 && y > 0){
28023 scale = targetWidth / width;
28025 if(width < height){
28026 scale = targetHeight / height;
28030 context.scale(scale, scale);
28032 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28033 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28035 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28036 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28038 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28039 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28041 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28046 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28047 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28049 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28050 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28052 var targetWidth = this.minWidth - 2 * x;
28053 var targetHeight = this.minHeight - 2 * y;
28057 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28058 scale = targetWidth / width;
28061 if(x > 0 && y == 0){
28062 scale = targetHeight / height;
28065 if(x > 0 && y > 0){
28066 scale = targetWidth / width;
28068 if(width < height){
28069 scale = targetHeight / height;
28073 context.scale(scale, scale);
28075 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28076 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28078 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28079 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28081 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28083 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28090 this.cropData = canvas.toDataURL(this.cropType);
28092 if(this.fireEvent('crop', this, this.cropData) !== false){
28093 this.process(this.file, this.cropData);
28100 setThumbBoxSize : function()
28104 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28105 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28106 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28108 this.minWidth = width;
28109 this.minHeight = height;
28111 if(this.rotate == 90 || this.rotate == 270){
28112 this.minWidth = height;
28113 this.minHeight = width;
28118 width = Math.ceil(this.minWidth * height / this.minHeight);
28120 if(this.minWidth > this.minHeight){
28122 height = Math.ceil(this.minHeight * width / this.minWidth);
28125 this.thumbEl.setStyle({
28126 width : width + 'px',
28127 height : height + 'px'
28134 setThumbBoxPosition : function()
28136 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28137 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28139 this.thumbEl.setLeft(x);
28140 this.thumbEl.setTop(y);
28144 baseRotateLevel : function()
28146 this.baseRotate = 1;
28149 typeof(this.exif) != 'undefined' &&
28150 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28151 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28153 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28156 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28160 baseScaleLevel : function()
28164 if(this.isDocument){
28166 if(this.baseRotate == 6 || this.baseRotate == 8){
28168 height = this.thumbEl.getHeight();
28169 this.baseScale = height / this.imageEl.OriginWidth;
28171 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28172 width = this.thumbEl.getWidth();
28173 this.baseScale = width / this.imageEl.OriginHeight;
28179 height = this.thumbEl.getHeight();
28180 this.baseScale = height / this.imageEl.OriginHeight;
28182 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28183 width = this.thumbEl.getWidth();
28184 this.baseScale = width / this.imageEl.OriginWidth;
28190 if(this.baseRotate == 6 || this.baseRotate == 8){
28192 width = this.thumbEl.getHeight();
28193 this.baseScale = width / this.imageEl.OriginHeight;
28195 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28196 height = this.thumbEl.getWidth();
28197 this.baseScale = height / this.imageEl.OriginHeight;
28200 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28201 height = this.thumbEl.getWidth();
28202 this.baseScale = height / this.imageEl.OriginHeight;
28204 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28205 width = this.thumbEl.getHeight();
28206 this.baseScale = width / this.imageEl.OriginWidth;
28213 width = this.thumbEl.getWidth();
28214 this.baseScale = width / this.imageEl.OriginWidth;
28216 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28217 height = this.thumbEl.getHeight();
28218 this.baseScale = height / this.imageEl.OriginHeight;
28221 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28223 height = this.thumbEl.getHeight();
28224 this.baseScale = height / this.imageEl.OriginHeight;
28226 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28227 width = this.thumbEl.getWidth();
28228 this.baseScale = width / this.imageEl.OriginWidth;
28236 getScaleLevel : function()
28238 return this.baseScale * Math.pow(1.1, this.scale);
28241 onTouchStart : function(e)
28243 if(!this.canvasLoaded){
28244 this.beforeSelectFile(e);
28248 var touches = e.browserEvent.touches;
28254 if(touches.length == 1){
28255 this.onMouseDown(e);
28259 if(touches.length != 2){
28265 for(var i = 0, finger; finger = touches[i]; i++){
28266 coords.push(finger.pageX, finger.pageY);
28269 var x = Math.pow(coords[0] - coords[2], 2);
28270 var y = Math.pow(coords[1] - coords[3], 2);
28272 this.startDistance = Math.sqrt(x + y);
28274 this.startScale = this.scale;
28276 this.pinching = true;
28277 this.dragable = false;
28281 onTouchMove : function(e)
28283 if(!this.pinching && !this.dragable){
28287 var touches = e.browserEvent.touches;
28294 this.onMouseMove(e);
28300 for(var i = 0, finger; finger = touches[i]; i++){
28301 coords.push(finger.pageX, finger.pageY);
28304 var x = Math.pow(coords[0] - coords[2], 2);
28305 var y = Math.pow(coords[1] - coords[3], 2);
28307 this.endDistance = Math.sqrt(x + y);
28309 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28311 if(!this.zoomable()){
28312 this.scale = this.startScale;
28320 onTouchEnd : function(e)
28322 this.pinching = false;
28323 this.dragable = false;
28327 process : function(file, crop)
28330 this.maskEl.mask(this.loadingText);
28333 this.xhr = new XMLHttpRequest();
28335 file.xhr = this.xhr;
28337 this.xhr.open(this.method, this.url, true);
28340 "Accept": "application/json",
28341 "Cache-Control": "no-cache",
28342 "X-Requested-With": "XMLHttpRequest"
28345 for (var headerName in headers) {
28346 var headerValue = headers[headerName];
28348 this.xhr.setRequestHeader(headerName, headerValue);
28354 this.xhr.onload = function()
28356 _this.xhrOnLoad(_this.xhr);
28359 this.xhr.onerror = function()
28361 _this.xhrOnError(_this.xhr);
28364 var formData = new FormData();
28366 formData.append('returnHTML', 'NO');
28369 formData.append('crop', crop);
28372 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28373 formData.append(this.paramName, file, file.name);
28376 if(typeof(file.filename) != 'undefined'){
28377 formData.append('filename', file.filename);
28380 if(typeof(file.mimetype) != 'undefined'){
28381 formData.append('mimetype', file.mimetype);
28384 if(this.fireEvent('arrange', this, formData) != false){
28385 this.xhr.send(formData);
28389 xhrOnLoad : function(xhr)
28392 this.maskEl.unmask();
28395 if (xhr.readyState !== 4) {
28396 this.fireEvent('exception', this, xhr);
28400 var response = Roo.decode(xhr.responseText);
28402 if(!response.success){
28403 this.fireEvent('exception', this, xhr);
28407 var response = Roo.decode(xhr.responseText);
28409 this.fireEvent('upload', this, response);
28413 xhrOnError : function()
28416 this.maskEl.unmask();
28419 Roo.log('xhr on error');
28421 var response = Roo.decode(xhr.responseText);
28427 prepare : function(file)
28430 this.maskEl.mask(this.loadingText);
28436 if(typeof(file) === 'string'){
28437 this.loadCanvas(file);
28441 if(!file || !this.urlAPI){
28446 this.cropType = file.type;
28450 if(this.fireEvent('prepare', this, this.file) != false){
28452 var reader = new FileReader();
28454 reader.onload = function (e) {
28455 if (e.target.error) {
28456 Roo.log(e.target.error);
28460 var buffer = e.target.result,
28461 dataView = new DataView(buffer),
28463 maxOffset = dataView.byteLength - 4,
28467 if (dataView.getUint16(0) === 0xffd8) {
28468 while (offset < maxOffset) {
28469 markerBytes = dataView.getUint16(offset);
28471 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28472 markerLength = dataView.getUint16(offset + 2) + 2;
28473 if (offset + markerLength > dataView.byteLength) {
28474 Roo.log('Invalid meta data: Invalid segment size.');
28478 if(markerBytes == 0xffe1){
28479 _this.parseExifData(
28486 offset += markerLength;
28496 var url = _this.urlAPI.createObjectURL(_this.file);
28498 _this.loadCanvas(url);
28503 reader.readAsArrayBuffer(this.file);
28509 parseExifData : function(dataView, offset, length)
28511 var tiffOffset = offset + 10,
28515 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28516 // No Exif data, might be XMP data instead
28520 // Check for the ASCII code for "Exif" (0x45786966):
28521 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28522 // No Exif data, might be XMP data instead
28525 if (tiffOffset + 8 > dataView.byteLength) {
28526 Roo.log('Invalid Exif data: Invalid segment size.');
28529 // Check for the two null bytes:
28530 if (dataView.getUint16(offset + 8) !== 0x0000) {
28531 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28534 // Check the byte alignment:
28535 switch (dataView.getUint16(tiffOffset)) {
28537 littleEndian = true;
28540 littleEndian = false;
28543 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28546 // Check for the TIFF tag marker (0x002A):
28547 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28548 Roo.log('Invalid Exif data: Missing TIFF marker.');
28551 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28552 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28554 this.parseExifTags(
28557 tiffOffset + dirOffset,
28562 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28567 if (dirOffset + 6 > dataView.byteLength) {
28568 Roo.log('Invalid Exif data: Invalid directory offset.');
28571 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28572 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28573 if (dirEndOffset + 4 > dataView.byteLength) {
28574 Roo.log('Invalid Exif data: Invalid directory size.');
28577 for (i = 0; i < tagsNumber; i += 1) {
28581 dirOffset + 2 + 12 * i, // tag offset
28585 // Return the offset to the next directory:
28586 return dataView.getUint32(dirEndOffset, littleEndian);
28589 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28591 var tag = dataView.getUint16(offset, littleEndian);
28593 this.exif[tag] = this.getExifValue(
28597 dataView.getUint16(offset + 2, littleEndian), // tag type
28598 dataView.getUint32(offset + 4, littleEndian), // tag length
28603 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28605 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28614 Roo.log('Invalid Exif data: Invalid tag type.');
28618 tagSize = tagType.size * length;
28619 // Determine if the value is contained in the dataOffset bytes,
28620 // or if the value at the dataOffset is a pointer to the actual data:
28621 dataOffset = tagSize > 4 ?
28622 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28623 if (dataOffset + tagSize > dataView.byteLength) {
28624 Roo.log('Invalid Exif data: Invalid data offset.');
28627 if (length === 1) {
28628 return tagType.getValue(dataView, dataOffset, littleEndian);
28631 for (i = 0; i < length; i += 1) {
28632 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28635 if (tagType.ascii) {
28637 // Concatenate the chars:
28638 for (i = 0; i < values.length; i += 1) {
28640 // Ignore the terminating NULL byte(s):
28641 if (c === '\u0000') {
28653 Roo.apply(Roo.bootstrap.UploadCropbox, {
28655 'Orientation': 0x0112
28659 1: 0, //'top-left',
28661 3: 180, //'bottom-right',
28662 // 4: 'bottom-left',
28664 6: 90, //'right-top',
28665 // 7: 'right-bottom',
28666 8: 270 //'left-bottom'
28670 // byte, 8-bit unsigned int:
28672 getValue: function (dataView, dataOffset) {
28673 return dataView.getUint8(dataOffset);
28677 // ascii, 8-bit byte:
28679 getValue: function (dataView, dataOffset) {
28680 return String.fromCharCode(dataView.getUint8(dataOffset));
28685 // short, 16 bit int:
28687 getValue: function (dataView, dataOffset, littleEndian) {
28688 return dataView.getUint16(dataOffset, littleEndian);
28692 // long, 32 bit int:
28694 getValue: function (dataView, dataOffset, littleEndian) {
28695 return dataView.getUint32(dataOffset, littleEndian);
28699 // rational = two long values, first is numerator, second is denominator:
28701 getValue: function (dataView, dataOffset, littleEndian) {
28702 return dataView.getUint32(dataOffset, littleEndian) /
28703 dataView.getUint32(dataOffset + 4, littleEndian);
28707 // slong, 32 bit signed int:
28709 getValue: function (dataView, dataOffset, littleEndian) {
28710 return dataView.getInt32(dataOffset, littleEndian);
28714 // srational, two slongs, first is numerator, second is denominator:
28716 getValue: function (dataView, dataOffset, littleEndian) {
28717 return dataView.getInt32(dataOffset, littleEndian) /
28718 dataView.getInt32(dataOffset + 4, littleEndian);
28728 cls : 'btn-group roo-upload-cropbox-rotate-left',
28729 action : 'rotate-left',
28733 cls : 'btn btn-default',
28734 html : '<i class="fa fa-undo"></i>'
28740 cls : 'btn-group roo-upload-cropbox-picture',
28741 action : 'picture',
28745 cls : 'btn btn-default',
28746 html : '<i class="fa fa-picture-o"></i>'
28752 cls : 'btn-group roo-upload-cropbox-rotate-right',
28753 action : 'rotate-right',
28757 cls : 'btn btn-default',
28758 html : '<i class="fa fa-repeat"></i>'
28766 cls : 'btn-group roo-upload-cropbox-rotate-left',
28767 action : 'rotate-left',
28771 cls : 'btn btn-default',
28772 html : '<i class="fa fa-undo"></i>'
28778 cls : 'btn-group roo-upload-cropbox-download',
28779 action : 'download',
28783 cls : 'btn btn-default',
28784 html : '<i class="fa fa-download"></i>'
28790 cls : 'btn-group roo-upload-cropbox-crop',
28795 cls : 'btn btn-default',
28796 html : '<i class="fa fa-crop"></i>'
28802 cls : 'btn-group roo-upload-cropbox-trash',
28807 cls : 'btn btn-default',
28808 html : '<i class="fa fa-trash"></i>'
28814 cls : 'btn-group roo-upload-cropbox-rotate-right',
28815 action : 'rotate-right',
28819 cls : 'btn btn-default',
28820 html : '<i class="fa fa-repeat"></i>'
28828 cls : 'btn-group roo-upload-cropbox-rotate-left',
28829 action : 'rotate-left',
28833 cls : 'btn btn-default',
28834 html : '<i class="fa fa-undo"></i>'
28840 cls : 'btn-group roo-upload-cropbox-rotate-right',
28841 action : 'rotate-right',
28845 cls : 'btn btn-default',
28846 html : '<i class="fa fa-repeat"></i>'
28859 * @class Roo.bootstrap.DocumentManager
28860 * @extends Roo.bootstrap.Component
28861 * Bootstrap DocumentManager class
28862 * @cfg {String} paramName default 'imageUpload'
28863 * @cfg {String} toolTipName default 'filename'
28864 * @cfg {String} method default POST
28865 * @cfg {String} url action url
28866 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28867 * @cfg {Boolean} multiple multiple upload default true
28868 * @cfg {Number} thumbSize default 300
28869 * @cfg {String} fieldLabel
28870 * @cfg {Number} labelWidth default 4
28871 * @cfg {String} labelAlign (left|top) default left
28872 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28873 * @cfg {Number} labellg set the width of label (1-12)
28874 * @cfg {Number} labelmd set the width of label (1-12)
28875 * @cfg {Number} labelsm set the width of label (1-12)
28876 * @cfg {Number} labelxs set the width of label (1-12)
28879 * Create a new DocumentManager
28880 * @param {Object} config The config object
28883 Roo.bootstrap.DocumentManager = function(config){
28884 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28887 this.delegates = [];
28892 * Fire when initial the DocumentManager
28893 * @param {Roo.bootstrap.DocumentManager} this
28898 * inspect selected file
28899 * @param {Roo.bootstrap.DocumentManager} this
28900 * @param {File} file
28905 * Fire when xhr load exception
28906 * @param {Roo.bootstrap.DocumentManager} this
28907 * @param {XMLHttpRequest} xhr
28909 "exception" : true,
28911 * @event afterupload
28912 * Fire when xhr load exception
28913 * @param {Roo.bootstrap.DocumentManager} this
28914 * @param {XMLHttpRequest} xhr
28916 "afterupload" : true,
28919 * prepare the form data
28920 * @param {Roo.bootstrap.DocumentManager} this
28921 * @param {Object} formData
28926 * Fire when remove the file
28927 * @param {Roo.bootstrap.DocumentManager} this
28928 * @param {Object} file
28933 * Fire after refresh the file
28934 * @param {Roo.bootstrap.DocumentManager} this
28939 * Fire after click the image
28940 * @param {Roo.bootstrap.DocumentManager} this
28941 * @param {Object} file
28946 * Fire when upload a image and editable set to true
28947 * @param {Roo.bootstrap.DocumentManager} this
28948 * @param {Object} file
28952 * @event beforeselectfile
28953 * Fire before select file
28954 * @param {Roo.bootstrap.DocumentManager} this
28956 "beforeselectfile" : true,
28959 * Fire before process file
28960 * @param {Roo.bootstrap.DocumentManager} this
28961 * @param {Object} file
28965 * @event previewrendered
28966 * Fire when preview rendered
28967 * @param {Roo.bootstrap.DocumentManager} this
28968 * @param {Object} file
28970 "previewrendered" : true,
28973 "previewResize" : true
28978 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28987 paramName : 'imageUpload',
28988 toolTipName : 'filename',
28991 labelAlign : 'left',
29001 getAutoCreate : function()
29003 var managerWidget = {
29005 cls : 'roo-document-manager',
29009 cls : 'roo-document-manager-selector',
29014 cls : 'roo-document-manager-uploader',
29018 cls : 'roo-document-manager-upload-btn',
29019 html : '<i class="fa fa-plus"></i>'
29030 cls : 'column col-md-12',
29035 if(this.fieldLabel.length){
29040 cls : 'column col-md-12',
29041 html : this.fieldLabel
29045 cls : 'column col-md-12',
29050 if(this.labelAlign == 'left'){
29055 html : this.fieldLabel
29064 if(this.labelWidth > 12){
29065 content[0].style = "width: " + this.labelWidth + 'px';
29068 if(this.labelWidth < 13 && this.labelmd == 0){
29069 this.labelmd = this.labelWidth;
29072 if(this.labellg > 0){
29073 content[0].cls += ' col-lg-' + this.labellg;
29074 content[1].cls += ' col-lg-' + (12 - this.labellg);
29077 if(this.labelmd > 0){
29078 content[0].cls += ' col-md-' + this.labelmd;
29079 content[1].cls += ' col-md-' + (12 - this.labelmd);
29082 if(this.labelsm > 0){
29083 content[0].cls += ' col-sm-' + this.labelsm;
29084 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29087 if(this.labelxs > 0){
29088 content[0].cls += ' col-xs-' + this.labelxs;
29089 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29097 cls : 'row clearfix',
29105 initEvents : function()
29107 this.managerEl = this.el.select('.roo-document-manager', true).first();
29108 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29110 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29111 this.selectorEl.hide();
29114 this.selectorEl.attr('multiple', 'multiple');
29117 this.selectorEl.on('change', this.onFileSelected, this);
29119 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29120 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29122 this.uploader.on('click', this.onUploaderClick, this);
29124 this.renderProgressDialog();
29128 window.addEventListener("resize", function() { _this.refresh(); } );
29130 this.fireEvent('initial', this);
29133 renderProgressDialog : function()
29137 this.progressDialog = new Roo.bootstrap.Modal({
29138 cls : 'roo-document-manager-progress-dialog',
29139 allow_close : false,
29149 btnclick : function() {
29150 _this.uploadCancel();
29156 this.progressDialog.render(Roo.get(document.body));
29158 this.progress = new Roo.bootstrap.Progress({
29159 cls : 'roo-document-manager-progress',
29164 this.progress.render(this.progressDialog.getChildContainer());
29166 this.progressBar = new Roo.bootstrap.ProgressBar({
29167 cls : 'roo-document-manager-progress-bar',
29170 aria_valuemax : 12,
29174 this.progressBar.render(this.progress.getChildContainer());
29177 onUploaderClick : function(e)
29179 e.preventDefault();
29181 if(this.fireEvent('beforeselectfile', this) != false){
29182 this.selectorEl.dom.click();
29187 onFileSelected : function(e)
29189 e.preventDefault();
29191 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29195 Roo.each(this.selectorEl.dom.files, function(file){
29196 if(this.fireEvent('inspect', this, file) != false){
29197 this.files.push(file);
29207 this.selectorEl.dom.value = '';
29209 if(!this.files || !this.files.length){
29213 if(this.boxes > 0 && this.files.length > this.boxes){
29214 this.files = this.files.slice(0, this.boxes);
29217 this.uploader.show();
29219 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29220 this.uploader.hide();
29229 Roo.each(this.files, function(file){
29231 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29232 var f = this.renderPreview(file);
29237 if(file.type.indexOf('image') != -1){
29238 this.delegates.push(
29240 _this.process(file);
29241 }).createDelegate(this)
29249 _this.process(file);
29250 }).createDelegate(this)
29255 this.files = files;
29257 this.delegates = this.delegates.concat(docs);
29259 if(!this.delegates.length){
29264 this.progressBar.aria_valuemax = this.delegates.length;
29271 arrange : function()
29273 if(!this.delegates.length){
29274 this.progressDialog.hide();
29279 var delegate = this.delegates.shift();
29281 this.progressDialog.show();
29283 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29285 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29290 refresh : function()
29292 this.uploader.show();
29294 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29295 this.uploader.hide();
29298 Roo.isTouch ? this.closable(false) : this.closable(true);
29300 this.fireEvent('refresh', this);
29303 onRemove : function(e, el, o)
29305 e.preventDefault();
29307 this.fireEvent('remove', this, o);
29311 remove : function(o)
29315 Roo.each(this.files, function(file){
29316 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29325 this.files = files;
29332 Roo.each(this.files, function(file){
29337 file.target.remove();
29346 onClick : function(e, el, o)
29348 e.preventDefault();
29350 this.fireEvent('click', this, o);
29354 closable : function(closable)
29356 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29358 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29370 xhrOnLoad : function(xhr)
29372 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29376 if (xhr.readyState !== 4) {
29378 this.fireEvent('exception', this, xhr);
29382 var response = Roo.decode(xhr.responseText);
29384 if(!response.success){
29386 this.fireEvent('exception', this, xhr);
29390 var file = this.renderPreview(response.data);
29392 this.files.push(file);
29396 this.fireEvent('afterupload', this, xhr);
29400 xhrOnError : function(xhr)
29402 Roo.log('xhr on error');
29404 var response = Roo.decode(xhr.responseText);
29411 process : function(file)
29413 if(this.fireEvent('process', this, file) !== false){
29414 if(this.editable && file.type.indexOf('image') != -1){
29415 this.fireEvent('edit', this, file);
29419 this.uploadStart(file, false);
29426 uploadStart : function(file, crop)
29428 this.xhr = new XMLHttpRequest();
29430 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29435 file.xhr = this.xhr;
29437 this.managerEl.createChild({
29439 cls : 'roo-document-manager-loading',
29443 tooltip : file.name,
29444 cls : 'roo-document-manager-thumb',
29445 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29451 this.xhr.open(this.method, this.url, true);
29454 "Accept": "application/json",
29455 "Cache-Control": "no-cache",
29456 "X-Requested-With": "XMLHttpRequest"
29459 for (var headerName in headers) {
29460 var headerValue = headers[headerName];
29462 this.xhr.setRequestHeader(headerName, headerValue);
29468 this.xhr.onload = function()
29470 _this.xhrOnLoad(_this.xhr);
29473 this.xhr.onerror = function()
29475 _this.xhrOnError(_this.xhr);
29478 var formData = new FormData();
29480 formData.append('returnHTML', 'NO');
29483 formData.append('crop', crop);
29486 formData.append(this.paramName, file, file.name);
29493 if(this.fireEvent('prepare', this, formData, options) != false){
29495 if(options.manually){
29499 this.xhr.send(formData);
29503 this.uploadCancel();
29506 uploadCancel : function()
29512 this.delegates = [];
29514 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29521 renderPreview : function(file)
29523 if(typeof(file.target) != 'undefined' && file.target){
29527 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29529 var previewEl = this.managerEl.createChild({
29531 cls : 'roo-document-manager-preview',
29535 tooltip : file[this.toolTipName],
29536 cls : 'roo-document-manager-thumb',
29537 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29542 html : '<i class="fa fa-times-circle"></i>'
29547 var close = previewEl.select('button.close', true).first();
29549 close.on('click', this.onRemove, this, file);
29551 file.target = previewEl;
29553 var image = previewEl.select('img', true).first();
29557 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29559 image.on('click', this.onClick, this, file);
29561 this.fireEvent('previewrendered', this, file);
29567 onPreviewLoad : function(file, image)
29569 if(typeof(file.target) == 'undefined' || !file.target){
29573 var width = image.dom.naturalWidth || image.dom.width;
29574 var height = image.dom.naturalHeight || image.dom.height;
29576 if(!this.previewResize) {
29580 if(width > height){
29581 file.target.addClass('wide');
29585 file.target.addClass('tall');
29590 uploadFromSource : function(file, crop)
29592 this.xhr = new XMLHttpRequest();
29594 this.managerEl.createChild({
29596 cls : 'roo-document-manager-loading',
29600 tooltip : file.name,
29601 cls : 'roo-document-manager-thumb',
29602 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29608 this.xhr.open(this.method, this.url, true);
29611 "Accept": "application/json",
29612 "Cache-Control": "no-cache",
29613 "X-Requested-With": "XMLHttpRequest"
29616 for (var headerName in headers) {
29617 var headerValue = headers[headerName];
29619 this.xhr.setRequestHeader(headerName, headerValue);
29625 this.xhr.onload = function()
29627 _this.xhrOnLoad(_this.xhr);
29630 this.xhr.onerror = function()
29632 _this.xhrOnError(_this.xhr);
29635 var formData = new FormData();
29637 formData.append('returnHTML', 'NO');
29639 formData.append('crop', crop);
29641 if(typeof(file.filename) != 'undefined'){
29642 formData.append('filename', file.filename);
29645 if(typeof(file.mimetype) != 'undefined'){
29646 formData.append('mimetype', file.mimetype);
29651 if(this.fireEvent('prepare', this, formData) != false){
29652 this.xhr.send(formData);
29662 * @class Roo.bootstrap.DocumentViewer
29663 * @extends Roo.bootstrap.Component
29664 * Bootstrap DocumentViewer class
29665 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29666 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29669 * Create a new DocumentViewer
29670 * @param {Object} config The config object
29673 Roo.bootstrap.DocumentViewer = function(config){
29674 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29679 * Fire after initEvent
29680 * @param {Roo.bootstrap.DocumentViewer} this
29686 * @param {Roo.bootstrap.DocumentViewer} this
29691 * Fire after download button
29692 * @param {Roo.bootstrap.DocumentViewer} this
29697 * Fire after trash button
29698 * @param {Roo.bootstrap.DocumentViewer} this
29705 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29707 showDownload : true,
29711 getAutoCreate : function()
29715 cls : 'roo-document-viewer',
29719 cls : 'roo-document-viewer-body',
29723 cls : 'roo-document-viewer-thumb',
29727 cls : 'roo-document-viewer-image'
29735 cls : 'roo-document-viewer-footer',
29738 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29742 cls : 'btn-group roo-document-viewer-download',
29746 cls : 'btn btn-default',
29747 html : '<i class="fa fa-download"></i>'
29753 cls : 'btn-group roo-document-viewer-trash',
29757 cls : 'btn btn-default',
29758 html : '<i class="fa fa-trash"></i>'
29771 initEvents : function()
29773 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29774 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29776 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29777 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29779 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29780 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29782 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29783 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29785 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29786 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29788 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29789 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29791 this.bodyEl.on('click', this.onClick, this);
29792 this.downloadBtn.on('click', this.onDownload, this);
29793 this.trashBtn.on('click', this.onTrash, this);
29795 this.downloadBtn.hide();
29796 this.trashBtn.hide();
29798 if(this.showDownload){
29799 this.downloadBtn.show();
29802 if(this.showTrash){
29803 this.trashBtn.show();
29806 if(!this.showDownload && !this.showTrash) {
29807 this.footerEl.hide();
29812 initial : function()
29814 this.fireEvent('initial', this);
29818 onClick : function(e)
29820 e.preventDefault();
29822 this.fireEvent('click', this);
29825 onDownload : function(e)
29827 e.preventDefault();
29829 this.fireEvent('download', this);
29832 onTrash : function(e)
29834 e.preventDefault();
29836 this.fireEvent('trash', this);
29848 * @class Roo.bootstrap.NavProgressBar
29849 * @extends Roo.bootstrap.Component
29850 * Bootstrap NavProgressBar class
29853 * Create a new nav progress bar
29854 * @param {Object} config The config object
29857 Roo.bootstrap.NavProgressBar = function(config){
29858 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29860 this.bullets = this.bullets || [];
29862 // Roo.bootstrap.NavProgressBar.register(this);
29866 * Fires when the active item changes
29867 * @param {Roo.bootstrap.NavProgressBar} this
29868 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29869 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29876 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29881 getAutoCreate : function()
29883 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29887 cls : 'roo-navigation-bar-group',
29891 cls : 'roo-navigation-top-bar'
29895 cls : 'roo-navigation-bullets-bar',
29899 cls : 'roo-navigation-bar'
29906 cls : 'roo-navigation-bottom-bar'
29916 initEvents: function()
29921 onRender : function(ct, position)
29923 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29925 if(this.bullets.length){
29926 Roo.each(this.bullets, function(b){
29935 addItem : function(cfg)
29937 var item = new Roo.bootstrap.NavProgressItem(cfg);
29939 item.parentId = this.id;
29940 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29943 var top = new Roo.bootstrap.Element({
29945 cls : 'roo-navigation-bar-text'
29948 var bottom = new Roo.bootstrap.Element({
29950 cls : 'roo-navigation-bar-text'
29953 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29954 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29956 var topText = new Roo.bootstrap.Element({
29958 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29961 var bottomText = new Roo.bootstrap.Element({
29963 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29966 topText.onRender(top.el, null);
29967 bottomText.onRender(bottom.el, null);
29970 item.bottomEl = bottom;
29973 this.barItems.push(item);
29978 getActive : function()
29980 var active = false;
29982 Roo.each(this.barItems, function(v){
29984 if (!v.isActive()) {
29996 setActiveItem : function(item)
30000 Roo.each(this.barItems, function(v){
30001 if (v.rid == item.rid) {
30005 if (v.isActive()) {
30006 v.setActive(false);
30011 item.setActive(true);
30013 this.fireEvent('changed', this, item, prev);
30016 getBarItem: function(rid)
30020 Roo.each(this.barItems, function(e) {
30021 if (e.rid != rid) {
30032 indexOfItem : function(item)
30036 Roo.each(this.barItems, function(v, i){
30038 if (v.rid != item.rid) {
30049 setActiveNext : function()
30051 var i = this.indexOfItem(this.getActive());
30053 if (i > this.barItems.length) {
30057 this.setActiveItem(this.barItems[i+1]);
30060 setActivePrev : function()
30062 var i = this.indexOfItem(this.getActive());
30068 this.setActiveItem(this.barItems[i-1]);
30071 format : function()
30073 if(!this.barItems.length){
30077 var width = 100 / this.barItems.length;
30079 Roo.each(this.barItems, function(i){
30080 i.el.setStyle('width', width + '%');
30081 i.topEl.el.setStyle('width', width + '%');
30082 i.bottomEl.el.setStyle('width', width + '%');
30091 * Nav Progress Item
30096 * @class Roo.bootstrap.NavProgressItem
30097 * @extends Roo.bootstrap.Component
30098 * Bootstrap NavProgressItem class
30099 * @cfg {String} rid the reference id
30100 * @cfg {Boolean} active (true|false) Is item active default false
30101 * @cfg {Boolean} disabled (true|false) Is item active default false
30102 * @cfg {String} html
30103 * @cfg {String} position (top|bottom) text position default bottom
30104 * @cfg {String} icon show icon instead of number
30107 * Create a new NavProgressItem
30108 * @param {Object} config The config object
30110 Roo.bootstrap.NavProgressItem = function(config){
30111 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30116 * The raw click event for the entire grid.
30117 * @param {Roo.bootstrap.NavProgressItem} this
30118 * @param {Roo.EventObject} e
30125 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30131 position : 'bottom',
30134 getAutoCreate : function()
30136 var iconCls = 'roo-navigation-bar-item-icon';
30138 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30142 cls: 'roo-navigation-bar-item',
30152 cfg.cls += ' active';
30155 cfg.cls += ' disabled';
30161 disable : function()
30163 this.setDisabled(true);
30166 enable : function()
30168 this.setDisabled(false);
30171 initEvents: function()
30173 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30175 this.iconEl.on('click', this.onClick, this);
30178 onClick : function(e)
30180 e.preventDefault();
30186 if(this.fireEvent('click', this, e) === false){
30190 this.parent().setActiveItem(this);
30193 isActive: function ()
30195 return this.active;
30198 setActive : function(state)
30200 if(this.active == state){
30204 this.active = state;
30207 this.el.addClass('active');
30211 this.el.removeClass('active');
30216 setDisabled : function(state)
30218 if(this.disabled == state){
30222 this.disabled = state;
30225 this.el.addClass('disabled');
30229 this.el.removeClass('disabled');
30232 tooltipEl : function()
30234 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30247 * @class Roo.bootstrap.FieldLabel
30248 * @extends Roo.bootstrap.Component
30249 * Bootstrap FieldLabel class
30250 * @cfg {String} html contents of the element
30251 * @cfg {String} tag tag of the element default label
30252 * @cfg {String} cls class of the element
30253 * @cfg {String} target label target
30254 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30255 * @cfg {String} invalidClass default "text-warning"
30256 * @cfg {String} validClass default "text-success"
30257 * @cfg {String} iconTooltip default "This field is required"
30258 * @cfg {String} indicatorpos (left|right) default left
30261 * Create a new FieldLabel
30262 * @param {Object} config The config object
30265 Roo.bootstrap.FieldLabel = function(config){
30266 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30271 * Fires after the field has been marked as invalid.
30272 * @param {Roo.form.FieldLabel} this
30273 * @param {String} msg The validation message
30278 * Fires after the field has been validated with no errors.
30279 * @param {Roo.form.FieldLabel} this
30285 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30292 invalidClass : 'has-warning',
30293 validClass : 'has-success',
30294 iconTooltip : 'This field is required',
30295 indicatorpos : 'left',
30297 getAutoCreate : function(){
30300 if (!this.allowBlank) {
30306 cls : 'roo-bootstrap-field-label ' + this.cls,
30311 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30312 tooltip : this.iconTooltip
30321 if(this.indicatorpos == 'right'){
30324 cls : 'roo-bootstrap-field-label ' + this.cls,
30333 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30334 tooltip : this.iconTooltip
30343 initEvents: function()
30345 Roo.bootstrap.Element.superclass.initEvents.call(this);
30347 this.indicator = this.indicatorEl();
30349 if(this.indicator){
30350 this.indicator.removeClass('visible');
30351 this.indicator.addClass('invisible');
30354 Roo.bootstrap.FieldLabel.register(this);
30357 indicatorEl : function()
30359 var indicator = this.el.select('i.roo-required-indicator',true).first();
30370 * Mark this field as valid
30372 markValid : function()
30374 if(this.indicator){
30375 this.indicator.removeClass('visible');
30376 this.indicator.addClass('invisible');
30379 this.el.removeClass(this.invalidClass);
30381 this.el.addClass(this.validClass);
30383 this.fireEvent('valid', this);
30387 * Mark this field as invalid
30388 * @param {String} msg The validation message
30390 markInvalid : function(msg)
30392 if(this.indicator){
30393 this.indicator.removeClass('invisible');
30394 this.indicator.addClass('visible');
30397 this.el.removeClass(this.validClass);
30399 this.el.addClass(this.invalidClass);
30401 this.fireEvent('invalid', this, msg);
30407 Roo.apply(Roo.bootstrap.FieldLabel, {
30412 * register a FieldLabel Group
30413 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30415 register : function(label)
30417 if(this.groups.hasOwnProperty(label.target)){
30421 this.groups[label.target] = label;
30425 * fetch a FieldLabel Group based on the target
30426 * @param {string} target
30427 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30429 get: function(target) {
30430 if (typeof(this.groups[target]) == 'undefined') {
30434 return this.groups[target] ;
30443 * page DateSplitField.
30449 * @class Roo.bootstrap.DateSplitField
30450 * @extends Roo.bootstrap.Component
30451 * Bootstrap DateSplitField class
30452 * @cfg {string} fieldLabel - the label associated
30453 * @cfg {Number} labelWidth set the width of label (0-12)
30454 * @cfg {String} labelAlign (top|left)
30455 * @cfg {Boolean} dayAllowBlank (true|false) default false
30456 * @cfg {Boolean} monthAllowBlank (true|false) default false
30457 * @cfg {Boolean} yearAllowBlank (true|false) default false
30458 * @cfg {string} dayPlaceholder
30459 * @cfg {string} monthPlaceholder
30460 * @cfg {string} yearPlaceholder
30461 * @cfg {string} dayFormat default 'd'
30462 * @cfg {string} monthFormat default 'm'
30463 * @cfg {string} yearFormat default 'Y'
30464 * @cfg {Number} labellg set the width of label (1-12)
30465 * @cfg {Number} labelmd set the width of label (1-12)
30466 * @cfg {Number} labelsm set the width of label (1-12)
30467 * @cfg {Number} labelxs set the width of label (1-12)
30471 * Create a new DateSplitField
30472 * @param {Object} config The config object
30475 Roo.bootstrap.DateSplitField = function(config){
30476 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30482 * getting the data of years
30483 * @param {Roo.bootstrap.DateSplitField} this
30484 * @param {Object} years
30489 * getting the data of days
30490 * @param {Roo.bootstrap.DateSplitField} this
30491 * @param {Object} days
30496 * Fires after the field has been marked as invalid.
30497 * @param {Roo.form.Field} this
30498 * @param {String} msg The validation message
30503 * Fires after the field has been validated with no errors.
30504 * @param {Roo.form.Field} this
30510 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30513 labelAlign : 'top',
30515 dayAllowBlank : false,
30516 monthAllowBlank : false,
30517 yearAllowBlank : false,
30518 dayPlaceholder : '',
30519 monthPlaceholder : '',
30520 yearPlaceholder : '',
30524 isFormField : true,
30530 getAutoCreate : function()
30534 cls : 'row roo-date-split-field-group',
30539 cls : 'form-hidden-field roo-date-split-field-group-value',
30545 var labelCls = 'col-md-12';
30546 var contentCls = 'col-md-4';
30548 if(this.fieldLabel){
30552 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30556 html : this.fieldLabel
30561 if(this.labelAlign == 'left'){
30563 if(this.labelWidth > 12){
30564 label.style = "width: " + this.labelWidth + 'px';
30567 if(this.labelWidth < 13 && this.labelmd == 0){
30568 this.labelmd = this.labelWidth;
30571 if(this.labellg > 0){
30572 labelCls = ' col-lg-' + this.labellg;
30573 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30576 if(this.labelmd > 0){
30577 labelCls = ' col-md-' + this.labelmd;
30578 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30581 if(this.labelsm > 0){
30582 labelCls = ' col-sm-' + this.labelsm;
30583 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30586 if(this.labelxs > 0){
30587 labelCls = ' col-xs-' + this.labelxs;
30588 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30592 label.cls += ' ' + labelCls;
30594 cfg.cn.push(label);
30597 Roo.each(['day', 'month', 'year'], function(t){
30600 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30607 inputEl: function ()
30609 return this.el.select('.roo-date-split-field-group-value', true).first();
30612 onRender : function(ct, position)
30616 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30618 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30620 this.dayField = new Roo.bootstrap.ComboBox({
30621 allowBlank : this.dayAllowBlank,
30622 alwaysQuery : true,
30623 displayField : 'value',
30626 forceSelection : true,
30628 placeholder : this.dayPlaceholder,
30629 selectOnFocus : true,
30630 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30631 triggerAction : 'all',
30633 valueField : 'value',
30634 store : new Roo.data.SimpleStore({
30635 data : (function() {
30637 _this.fireEvent('days', _this, days);
30640 fields : [ 'value' ]
30643 select : function (_self, record, index)
30645 _this.setValue(_this.getValue());
30650 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30652 this.monthField = new Roo.bootstrap.MonthField({
30653 after : '<i class=\"fa fa-calendar\"></i>',
30654 allowBlank : this.monthAllowBlank,
30655 placeholder : this.monthPlaceholder,
30658 render : function (_self)
30660 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30661 e.preventDefault();
30665 select : function (_self, oldvalue, newvalue)
30667 _this.setValue(_this.getValue());
30672 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30674 this.yearField = new Roo.bootstrap.ComboBox({
30675 allowBlank : this.yearAllowBlank,
30676 alwaysQuery : true,
30677 displayField : 'value',
30680 forceSelection : true,
30682 placeholder : this.yearPlaceholder,
30683 selectOnFocus : true,
30684 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30685 triggerAction : 'all',
30687 valueField : 'value',
30688 store : new Roo.data.SimpleStore({
30689 data : (function() {
30691 _this.fireEvent('years', _this, years);
30694 fields : [ 'value' ]
30697 select : function (_self, record, index)
30699 _this.setValue(_this.getValue());
30704 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30707 setValue : function(v, format)
30709 this.inputEl.dom.value = v;
30711 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30713 var d = Date.parseDate(v, f);
30720 this.setDay(d.format(this.dayFormat));
30721 this.setMonth(d.format(this.monthFormat));
30722 this.setYear(d.format(this.yearFormat));
30729 setDay : function(v)
30731 this.dayField.setValue(v);
30732 this.inputEl.dom.value = this.getValue();
30737 setMonth : function(v)
30739 this.monthField.setValue(v, true);
30740 this.inputEl.dom.value = this.getValue();
30745 setYear : function(v)
30747 this.yearField.setValue(v);
30748 this.inputEl.dom.value = this.getValue();
30753 getDay : function()
30755 return this.dayField.getValue();
30758 getMonth : function()
30760 return this.monthField.getValue();
30763 getYear : function()
30765 return this.yearField.getValue();
30768 getValue : function()
30770 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30772 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30782 this.inputEl.dom.value = '';
30787 validate : function()
30789 var d = this.dayField.validate();
30790 var m = this.monthField.validate();
30791 var y = this.yearField.validate();
30796 (!this.dayAllowBlank && !d) ||
30797 (!this.monthAllowBlank && !m) ||
30798 (!this.yearAllowBlank && !y)
30803 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30812 this.markInvalid();
30817 markValid : function()
30820 var label = this.el.select('label', true).first();
30821 var icon = this.el.select('i.fa-star', true).first();
30827 this.fireEvent('valid', this);
30831 * Mark this field as invalid
30832 * @param {String} msg The validation message
30834 markInvalid : function(msg)
30837 var label = this.el.select('label', true).first();
30838 var icon = this.el.select('i.fa-star', true).first();
30840 if(label && !icon){
30841 this.el.select('.roo-date-split-field-label', true).createChild({
30843 cls : 'text-danger fa fa-lg fa-star',
30844 tooltip : 'This field is required',
30845 style : 'margin-right:5px;'
30849 this.fireEvent('invalid', this, msg);
30852 clearInvalid : function()
30854 var label = this.el.select('label', true).first();
30855 var icon = this.el.select('i.fa-star', true).first();
30861 this.fireEvent('valid', this);
30864 getName: function()
30874 * http://masonry.desandro.com
30876 * The idea is to render all the bricks based on vertical width...
30878 * The original code extends 'outlayer' - we might need to use that....
30884 * @class Roo.bootstrap.LayoutMasonry
30885 * @extends Roo.bootstrap.Component
30886 * Bootstrap Layout Masonry class
30889 * Create a new Element
30890 * @param {Object} config The config object
30893 Roo.bootstrap.LayoutMasonry = function(config){
30895 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30899 Roo.bootstrap.LayoutMasonry.register(this);
30905 * Fire after layout the items
30906 * @param {Roo.bootstrap.LayoutMasonry} this
30907 * @param {Roo.EventObject} e
30914 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30917 * @cfg {Boolean} isLayoutInstant = no animation?
30919 isLayoutInstant : false, // needed?
30922 * @cfg {Number} boxWidth width of the columns
30927 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30932 * @cfg {Number} padWidth padding below box..
30937 * @cfg {Number} gutter gutter width..
30942 * @cfg {Number} maxCols maximum number of columns
30948 * @cfg {Boolean} isAutoInitial defalut true
30950 isAutoInitial : true,
30955 * @cfg {Boolean} isHorizontal defalut false
30957 isHorizontal : false,
30959 currentSize : null,
30965 bricks: null, //CompositeElement
30969 _isLayoutInited : false,
30971 // isAlternative : false, // only use for vertical layout...
30974 * @cfg {Number} alternativePadWidth padding below box..
30976 alternativePadWidth : 50,
30978 selectedBrick : [],
30980 getAutoCreate : function(){
30982 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30986 cls: 'blog-masonary-wrapper ' + this.cls,
30988 cls : 'mas-boxes masonary'
30995 getChildContainer: function( )
30997 if (this.boxesEl) {
30998 return this.boxesEl;
31001 this.boxesEl = this.el.select('.mas-boxes').first();
31003 return this.boxesEl;
31007 initEvents : function()
31011 if(this.isAutoInitial){
31012 Roo.log('hook children rendered');
31013 this.on('childrenrendered', function() {
31014 Roo.log('children rendered');
31020 initial : function()
31022 this.selectedBrick = [];
31024 this.currentSize = this.el.getBox(true);
31026 Roo.EventManager.onWindowResize(this.resize, this);
31028 if(!this.isAutoInitial){
31036 //this.layout.defer(500,this);
31040 resize : function()
31042 var cs = this.el.getBox(true);
31045 this.currentSize.width == cs.width &&
31046 this.currentSize.x == cs.x &&
31047 this.currentSize.height == cs.height &&
31048 this.currentSize.y == cs.y
31050 Roo.log("no change in with or X or Y");
31054 this.currentSize = cs;
31060 layout : function()
31062 this._resetLayout();
31064 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31066 this.layoutItems( isInstant );
31068 this._isLayoutInited = true;
31070 this.fireEvent('layout', this);
31074 _resetLayout : function()
31076 if(this.isHorizontal){
31077 this.horizontalMeasureColumns();
31081 this.verticalMeasureColumns();
31085 verticalMeasureColumns : function()
31087 this.getContainerWidth();
31089 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31090 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31094 var boxWidth = this.boxWidth + this.padWidth;
31096 if(this.containerWidth < this.boxWidth){
31097 boxWidth = this.containerWidth
31100 var containerWidth = this.containerWidth;
31102 var cols = Math.floor(containerWidth / boxWidth);
31104 this.cols = Math.max( cols, 1 );
31106 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31108 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31110 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31112 this.colWidth = boxWidth + avail - this.padWidth;
31114 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31115 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31118 horizontalMeasureColumns : function()
31120 this.getContainerWidth();
31122 var boxWidth = this.boxWidth;
31124 if(this.containerWidth < boxWidth){
31125 boxWidth = this.containerWidth;
31128 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31130 this.el.setHeight(boxWidth);
31134 getContainerWidth : function()
31136 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31139 layoutItems : function( isInstant )
31141 Roo.log(this.bricks);
31143 var items = Roo.apply([], this.bricks);
31145 if(this.isHorizontal){
31146 this._horizontalLayoutItems( items , isInstant );
31150 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31151 // this._verticalAlternativeLayoutItems( items , isInstant );
31155 this._verticalLayoutItems( items , isInstant );
31159 _verticalLayoutItems : function ( items , isInstant)
31161 if ( !items || !items.length ) {
31166 ['xs', 'xs', 'xs', 'tall'],
31167 ['xs', 'xs', 'tall'],
31168 ['xs', 'xs', 'sm'],
31169 ['xs', 'xs', 'xs'],
31175 ['sm', 'xs', 'xs'],
31179 ['tall', 'xs', 'xs', 'xs'],
31180 ['tall', 'xs', 'xs'],
31192 Roo.each(items, function(item, k){
31194 switch (item.size) {
31195 // these layouts take up a full box,
31206 boxes.push([item]);
31229 var filterPattern = function(box, length)
31237 var pattern = box.slice(0, length);
31241 Roo.each(pattern, function(i){
31242 format.push(i.size);
31245 Roo.each(standard, function(s){
31247 if(String(s) != String(format)){
31256 if(!match && length == 1){
31261 filterPattern(box, length - 1);
31265 queue.push(pattern);
31267 box = box.slice(length, box.length);
31269 filterPattern(box, 4);
31275 Roo.each(boxes, function(box, k){
31281 if(box.length == 1){
31286 filterPattern(box, 4);
31290 this._processVerticalLayoutQueue( queue, isInstant );
31294 // _verticalAlternativeLayoutItems : function( items , isInstant )
31296 // if ( !items || !items.length ) {
31300 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31304 _horizontalLayoutItems : function ( items , isInstant)
31306 if ( !items || !items.length || items.length < 3) {
31312 var eItems = items.slice(0, 3);
31314 items = items.slice(3, items.length);
31317 ['xs', 'xs', 'xs', 'wide'],
31318 ['xs', 'xs', 'wide'],
31319 ['xs', 'xs', 'sm'],
31320 ['xs', 'xs', 'xs'],
31326 ['sm', 'xs', 'xs'],
31330 ['wide', 'xs', 'xs', 'xs'],
31331 ['wide', 'xs', 'xs'],
31344 Roo.each(items, function(item, k){
31346 switch (item.size) {
31357 boxes.push([item]);
31381 var filterPattern = function(box, length)
31389 var pattern = box.slice(0, length);
31393 Roo.each(pattern, function(i){
31394 format.push(i.size);
31397 Roo.each(standard, function(s){
31399 if(String(s) != String(format)){
31408 if(!match && length == 1){
31413 filterPattern(box, length - 1);
31417 queue.push(pattern);
31419 box = box.slice(length, box.length);
31421 filterPattern(box, 4);
31427 Roo.each(boxes, function(box, k){
31433 if(box.length == 1){
31438 filterPattern(box, 4);
31445 var pos = this.el.getBox(true);
31449 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31451 var hit_end = false;
31453 Roo.each(queue, function(box){
31457 Roo.each(box, function(b){
31459 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31469 Roo.each(box, function(b){
31471 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31474 mx = Math.max(mx, b.x);
31478 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31482 Roo.each(box, function(b){
31484 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31498 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31501 /** Sets position of item in DOM
31502 * @param {Element} item
31503 * @param {Number} x - horizontal position
31504 * @param {Number} y - vertical position
31505 * @param {Boolean} isInstant - disables transitions
31507 _processVerticalLayoutQueue : function( queue, isInstant )
31509 var pos = this.el.getBox(true);
31514 for (var i = 0; i < this.cols; i++){
31518 Roo.each(queue, function(box, k){
31520 var col = k % this.cols;
31522 Roo.each(box, function(b,kk){
31524 b.el.position('absolute');
31526 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31527 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31529 if(b.size == 'md-left' || b.size == 'md-right'){
31530 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31531 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31534 b.el.setWidth(width);
31535 b.el.setHeight(height);
31537 b.el.select('iframe',true).setSize(width,height);
31541 for (var i = 0; i < this.cols; i++){
31543 if(maxY[i] < maxY[col]){
31548 col = Math.min(col, i);
31552 x = pos.x + col * (this.colWidth + this.padWidth);
31556 var positions = [];
31558 switch (box.length){
31560 positions = this.getVerticalOneBoxColPositions(x, y, box);
31563 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31566 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31569 positions = this.getVerticalFourBoxColPositions(x, y, box);
31575 Roo.each(box, function(b,kk){
31577 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31579 var sz = b.el.getSize();
31581 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31589 for (var i = 0; i < this.cols; i++){
31590 mY = Math.max(mY, maxY[i]);
31593 this.el.setHeight(mY - pos.y);
31597 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31599 // var pos = this.el.getBox(true);
31602 // var maxX = pos.right;
31604 // var maxHeight = 0;
31606 // Roo.each(items, function(item, k){
31610 // item.el.position('absolute');
31612 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31614 // item.el.setWidth(width);
31616 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31618 // item.el.setHeight(height);
31621 // item.el.setXY([x, y], isInstant ? false : true);
31623 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31626 // y = y + height + this.alternativePadWidth;
31628 // maxHeight = maxHeight + height + this.alternativePadWidth;
31632 // this.el.setHeight(maxHeight);
31636 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31638 var pos = this.el.getBox(true);
31643 var maxX = pos.right;
31645 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31647 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31649 Roo.each(queue, function(box, k){
31651 Roo.each(box, function(b, kk){
31653 b.el.position('absolute');
31655 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31656 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31658 if(b.size == 'md-left' || b.size == 'md-right'){
31659 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31660 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31663 b.el.setWidth(width);
31664 b.el.setHeight(height);
31672 var positions = [];
31674 switch (box.length){
31676 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31679 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31682 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31685 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31691 Roo.each(box, function(b,kk){
31693 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31695 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31703 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31705 Roo.each(eItems, function(b,k){
31707 b.size = (k == 0) ? 'sm' : 'xs';
31708 b.x = (k == 0) ? 2 : 1;
31709 b.y = (k == 0) ? 2 : 1;
31711 b.el.position('absolute');
31713 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31715 b.el.setWidth(width);
31717 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31719 b.el.setHeight(height);
31723 var positions = [];
31726 x : maxX - this.unitWidth * 2 - this.gutter,
31731 x : maxX - this.unitWidth,
31732 y : minY + (this.unitWidth + this.gutter) * 2
31736 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31740 Roo.each(eItems, function(b,k){
31742 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31748 getVerticalOneBoxColPositions : function(x, y, box)
31752 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31754 if(box[0].size == 'md-left'){
31758 if(box[0].size == 'md-right'){
31763 x : x + (this.unitWidth + this.gutter) * rand,
31770 getVerticalTwoBoxColPositions : function(x, y, box)
31774 if(box[0].size == 'xs'){
31778 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31782 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31796 x : x + (this.unitWidth + this.gutter) * 2,
31797 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31804 getVerticalThreeBoxColPositions : function(x, y, box)
31808 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31816 x : x + (this.unitWidth + this.gutter) * 1,
31821 x : x + (this.unitWidth + this.gutter) * 2,
31829 if(box[0].size == 'xs' && box[1].size == 'xs'){
31838 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31842 x : x + (this.unitWidth + this.gutter) * 1,
31856 x : x + (this.unitWidth + this.gutter) * 2,
31861 x : x + (this.unitWidth + this.gutter) * 2,
31862 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31869 getVerticalFourBoxColPositions : function(x, y, box)
31873 if(box[0].size == 'xs'){
31882 y : y + (this.unitHeight + this.gutter) * 1
31887 y : y + (this.unitHeight + this.gutter) * 2
31891 x : x + (this.unitWidth + this.gutter) * 1,
31905 x : x + (this.unitWidth + this.gutter) * 2,
31910 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31911 y : y + (this.unitHeight + this.gutter) * 1
31915 x : x + (this.unitWidth + this.gutter) * 2,
31916 y : y + (this.unitWidth + this.gutter) * 2
31923 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31927 if(box[0].size == 'md-left'){
31929 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31936 if(box[0].size == 'md-right'){
31938 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31939 y : minY + (this.unitWidth + this.gutter) * 1
31945 var rand = Math.floor(Math.random() * (4 - box[0].y));
31948 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31949 y : minY + (this.unitWidth + this.gutter) * rand
31956 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31960 if(box[0].size == 'xs'){
31963 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31968 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31969 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31977 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31982 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31983 y : minY + (this.unitWidth + this.gutter) * 2
31990 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31994 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31997 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32002 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32003 y : minY + (this.unitWidth + this.gutter) * 1
32007 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32008 y : minY + (this.unitWidth + this.gutter) * 2
32015 if(box[0].size == 'xs' && box[1].size == 'xs'){
32018 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32023 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32028 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32029 y : minY + (this.unitWidth + this.gutter) * 1
32037 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32042 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32043 y : minY + (this.unitWidth + this.gutter) * 2
32047 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32048 y : minY + (this.unitWidth + this.gutter) * 2
32055 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32059 if(box[0].size == 'xs'){
32062 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32067 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32072 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),
32077 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32078 y : minY + (this.unitWidth + this.gutter) * 1
32086 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32091 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32092 y : minY + (this.unitWidth + this.gutter) * 2
32096 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32097 y : minY + (this.unitWidth + this.gutter) * 2
32101 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),
32102 y : minY + (this.unitWidth + this.gutter) * 2
32110 * remove a Masonry Brick
32111 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32113 removeBrick : function(brick_id)
32119 for (var i = 0; i<this.bricks.length; i++) {
32120 if (this.bricks[i].id == brick_id) {
32121 this.bricks.splice(i,1);
32122 this.el.dom.removeChild(Roo.get(brick_id).dom);
32129 * adds a Masonry Brick
32130 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32132 addBrick : function(cfg)
32134 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32135 //this.register(cn);
32136 cn.parentId = this.id;
32137 cn.render(this.el);
32142 * register a Masonry Brick
32143 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32146 register : function(brick)
32148 this.bricks.push(brick);
32149 brick.masonryId = this.id;
32153 * clear all the Masonry Brick
32155 clearAll : function()
32158 //this.getChildContainer().dom.innerHTML = "";
32159 this.el.dom.innerHTML = '';
32162 getSelected : function()
32164 if (!this.selectedBrick) {
32168 return this.selectedBrick;
32172 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32176 * register a Masonry Layout
32177 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32180 register : function(layout)
32182 this.groups[layout.id] = layout;
32185 * fetch a Masonry Layout based on the masonry layout ID
32186 * @param {string} the masonry layout to add
32187 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32190 get: function(layout_id) {
32191 if (typeof(this.groups[layout_id]) == 'undefined') {
32194 return this.groups[layout_id] ;
32206 * http://masonry.desandro.com
32208 * The idea is to render all the bricks based on vertical width...
32210 * The original code extends 'outlayer' - we might need to use that....
32216 * @class Roo.bootstrap.LayoutMasonryAuto
32217 * @extends Roo.bootstrap.Component
32218 * Bootstrap Layout Masonry class
32221 * Create a new Element
32222 * @param {Object} config The config object
32225 Roo.bootstrap.LayoutMasonryAuto = function(config){
32226 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32229 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32232 * @cfg {Boolean} isFitWidth - resize the width..
32234 isFitWidth : false, // options..
32236 * @cfg {Boolean} isOriginLeft = left align?
32238 isOriginLeft : true,
32240 * @cfg {Boolean} isOriginTop = top align?
32242 isOriginTop : false,
32244 * @cfg {Boolean} isLayoutInstant = no animation?
32246 isLayoutInstant : false, // needed?
32248 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32250 isResizingContainer : true,
32252 * @cfg {Number} columnWidth width of the columns
32258 * @cfg {Number} maxCols maximum number of columns
32263 * @cfg {Number} padHeight padding below box..
32269 * @cfg {Boolean} isAutoInitial defalut true
32272 isAutoInitial : true,
32278 initialColumnWidth : 0,
32279 currentSize : null,
32281 colYs : null, // array.
32288 bricks: null, //CompositeElement
32289 cols : 0, // array?
32290 // element : null, // wrapped now this.el
32291 _isLayoutInited : null,
32294 getAutoCreate : function(){
32298 cls: 'blog-masonary-wrapper ' + this.cls,
32300 cls : 'mas-boxes masonary'
32307 getChildContainer: function( )
32309 if (this.boxesEl) {
32310 return this.boxesEl;
32313 this.boxesEl = this.el.select('.mas-boxes').first();
32315 return this.boxesEl;
32319 initEvents : function()
32323 if(this.isAutoInitial){
32324 Roo.log('hook children rendered');
32325 this.on('childrenrendered', function() {
32326 Roo.log('children rendered');
32333 initial : function()
32335 this.reloadItems();
32337 this.currentSize = this.el.getBox(true);
32339 /// was window resize... - let's see if this works..
32340 Roo.EventManager.onWindowResize(this.resize, this);
32342 if(!this.isAutoInitial){
32347 this.layout.defer(500,this);
32350 reloadItems: function()
32352 this.bricks = this.el.select('.masonry-brick', true);
32354 this.bricks.each(function(b) {
32355 //Roo.log(b.getSize());
32356 if (!b.attr('originalwidth')) {
32357 b.attr('originalwidth', b.getSize().width);
32362 Roo.log(this.bricks.elements.length);
32365 resize : function()
32368 var cs = this.el.getBox(true);
32370 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32371 Roo.log("no change in with or X");
32374 this.currentSize = cs;
32378 layout : function()
32381 this._resetLayout();
32382 //this._manageStamps();
32384 // don't animate first layout
32385 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32386 this.layoutItems( isInstant );
32388 // flag for initalized
32389 this._isLayoutInited = true;
32392 layoutItems : function( isInstant )
32394 //var items = this._getItemsForLayout( this.items );
32395 // original code supports filtering layout items.. we just ignore it..
32397 this._layoutItems( this.bricks , isInstant );
32399 this._postLayout();
32401 _layoutItems : function ( items , isInstant)
32403 //this.fireEvent( 'layout', this, items );
32406 if ( !items || !items.elements.length ) {
32407 // no items, emit event with empty array
32412 items.each(function(item) {
32413 Roo.log("layout item");
32415 // get x/y object from method
32416 var position = this._getItemLayoutPosition( item );
32418 position.item = item;
32419 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32420 queue.push( position );
32423 this._processLayoutQueue( queue );
32425 /** Sets position of item in DOM
32426 * @param {Element} item
32427 * @param {Number} x - horizontal position
32428 * @param {Number} y - vertical position
32429 * @param {Boolean} isInstant - disables transitions
32431 _processLayoutQueue : function( queue )
32433 for ( var i=0, len = queue.length; i < len; i++ ) {
32434 var obj = queue[i];
32435 obj.item.position('absolute');
32436 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32442 * Any logic you want to do after each layout,
32443 * i.e. size the container
32445 _postLayout : function()
32447 this.resizeContainer();
32450 resizeContainer : function()
32452 if ( !this.isResizingContainer ) {
32455 var size = this._getContainerSize();
32457 this.el.setSize(size.width,size.height);
32458 this.boxesEl.setSize(size.width,size.height);
32464 _resetLayout : function()
32466 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32467 this.colWidth = this.el.getWidth();
32468 //this.gutter = this.el.getWidth();
32470 this.measureColumns();
32476 this.colYs.push( 0 );
32482 measureColumns : function()
32484 this.getContainerWidth();
32485 // if columnWidth is 0, default to outerWidth of first item
32486 if ( !this.columnWidth ) {
32487 var firstItem = this.bricks.first();
32488 Roo.log(firstItem);
32489 this.columnWidth = this.containerWidth;
32490 if (firstItem && firstItem.attr('originalwidth') ) {
32491 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32493 // columnWidth fall back to item of first element
32494 Roo.log("set column width?");
32495 this.initialColumnWidth = this.columnWidth ;
32497 // if first elem has no width, default to size of container
32502 if (this.initialColumnWidth) {
32503 this.columnWidth = this.initialColumnWidth;
32508 // column width is fixed at the top - however if container width get's smaller we should
32511 // this bit calcs how man columns..
32513 var columnWidth = this.columnWidth += this.gutter;
32515 // calculate columns
32516 var containerWidth = this.containerWidth + this.gutter;
32518 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32519 // fix rounding errors, typically with gutters
32520 var excess = columnWidth - containerWidth % columnWidth;
32523 // if overshoot is less than a pixel, round up, otherwise floor it
32524 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32525 cols = Math[ mathMethod ]( cols );
32526 this.cols = Math.max( cols, 1 );
32527 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32529 // padding positioning..
32530 var totalColWidth = this.cols * this.columnWidth;
32531 var padavail = this.containerWidth - totalColWidth;
32532 // so for 2 columns - we need 3 'pads'
32534 var padNeeded = (1+this.cols) * this.padWidth;
32536 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32538 this.columnWidth += padExtra
32539 //this.padWidth = Math.floor(padavail / ( this.cols));
32541 // adjust colum width so that padding is fixed??
32543 // we have 3 columns ... total = width * 3
32544 // we have X left over... that should be used by
32546 //if (this.expandC) {
32554 getContainerWidth : function()
32556 /* // container is parent if fit width
32557 var container = this.isFitWidth ? this.element.parentNode : this.element;
32558 // check that this.size and size are there
32559 // IE8 triggers resize on body size change, so they might not be
32561 var size = getSize( container ); //FIXME
32562 this.containerWidth = size && size.innerWidth; //FIXME
32565 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32569 _getItemLayoutPosition : function( item ) // what is item?
32571 // we resize the item to our columnWidth..
32573 item.setWidth(this.columnWidth);
32574 item.autoBoxAdjust = false;
32576 var sz = item.getSize();
32578 // how many columns does this brick span
32579 var remainder = this.containerWidth % this.columnWidth;
32581 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32582 // round if off by 1 pixel, otherwise use ceil
32583 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32584 colSpan = Math.min( colSpan, this.cols );
32586 // normally this should be '1' as we dont' currently allow multi width columns..
32588 var colGroup = this._getColGroup( colSpan );
32589 // get the minimum Y value from the columns
32590 var minimumY = Math.min.apply( Math, colGroup );
32591 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32593 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32595 // position the brick
32597 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32598 y: this.currentSize.y + minimumY + this.padHeight
32602 // apply setHeight to necessary columns
32603 var setHeight = minimumY + sz.height + this.padHeight;
32604 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32606 var setSpan = this.cols + 1 - colGroup.length;
32607 for ( var i = 0; i < setSpan; i++ ) {
32608 this.colYs[ shortColIndex + i ] = setHeight ;
32615 * @param {Number} colSpan - number of columns the element spans
32616 * @returns {Array} colGroup
32618 _getColGroup : function( colSpan )
32620 if ( colSpan < 2 ) {
32621 // if brick spans only one column, use all the column Ys
32626 // how many different places could this brick fit horizontally
32627 var groupCount = this.cols + 1 - colSpan;
32628 // for each group potential horizontal position
32629 for ( var i = 0; i < groupCount; i++ ) {
32630 // make an array of colY values for that one group
32631 var groupColYs = this.colYs.slice( i, i + colSpan );
32632 // and get the max value of the array
32633 colGroup[i] = Math.max.apply( Math, groupColYs );
32638 _manageStamp : function( stamp )
32640 var stampSize = stamp.getSize();
32641 var offset = stamp.getBox();
32642 // get the columns that this stamp affects
32643 var firstX = this.isOriginLeft ? offset.x : offset.right;
32644 var lastX = firstX + stampSize.width;
32645 var firstCol = Math.floor( firstX / this.columnWidth );
32646 firstCol = Math.max( 0, firstCol );
32648 var lastCol = Math.floor( lastX / this.columnWidth );
32649 // lastCol should not go over if multiple of columnWidth #425
32650 lastCol -= lastX % this.columnWidth ? 0 : 1;
32651 lastCol = Math.min( this.cols - 1, lastCol );
32653 // set colYs to bottom of the stamp
32654 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32657 for ( var i = firstCol; i <= lastCol; i++ ) {
32658 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32663 _getContainerSize : function()
32665 this.maxY = Math.max.apply( Math, this.colYs );
32670 if ( this.isFitWidth ) {
32671 size.width = this._getContainerFitWidth();
32677 _getContainerFitWidth : function()
32679 var unusedCols = 0;
32680 // count unused columns
32683 if ( this.colYs[i] !== 0 ) {
32688 // fit container to columns that have been used
32689 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32692 needsResizeLayout : function()
32694 var previousWidth = this.containerWidth;
32695 this.getContainerWidth();
32696 return previousWidth !== this.containerWidth;
32711 * @class Roo.bootstrap.MasonryBrick
32712 * @extends Roo.bootstrap.Component
32713 * Bootstrap MasonryBrick class
32716 * Create a new MasonryBrick
32717 * @param {Object} config The config object
32720 Roo.bootstrap.MasonryBrick = function(config){
32722 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32724 Roo.bootstrap.MasonryBrick.register(this);
32730 * When a MasonryBrick is clcik
32731 * @param {Roo.bootstrap.MasonryBrick} this
32732 * @param {Roo.EventObject} e
32738 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32741 * @cfg {String} title
32745 * @cfg {String} html
32749 * @cfg {String} bgimage
32753 * @cfg {String} videourl
32757 * @cfg {String} cls
32761 * @cfg {String} href
32765 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32770 * @cfg {String} placetitle (center|bottom)
32775 * @cfg {Boolean} isFitContainer defalut true
32777 isFitContainer : true,
32780 * @cfg {Boolean} preventDefault defalut false
32782 preventDefault : false,
32785 * @cfg {Boolean} inverse defalut false
32787 maskInverse : false,
32789 getAutoCreate : function()
32791 if(!this.isFitContainer){
32792 return this.getSplitAutoCreate();
32795 var cls = 'masonry-brick masonry-brick-full';
32797 if(this.href.length){
32798 cls += ' masonry-brick-link';
32801 if(this.bgimage.length){
32802 cls += ' masonry-brick-image';
32805 if(this.maskInverse){
32806 cls += ' mask-inverse';
32809 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32810 cls += ' enable-mask';
32814 cls += ' masonry-' + this.size + '-brick';
32817 if(this.placetitle.length){
32819 switch (this.placetitle) {
32821 cls += ' masonry-center-title';
32824 cls += ' masonry-bottom-title';
32831 if(!this.html.length && !this.bgimage.length){
32832 cls += ' masonry-center-title';
32835 if(!this.html.length && this.bgimage.length){
32836 cls += ' masonry-bottom-title';
32841 cls += ' ' + this.cls;
32845 tag: (this.href.length) ? 'a' : 'div',
32850 cls: 'masonry-brick-mask'
32854 cls: 'masonry-brick-paragraph',
32860 if(this.href.length){
32861 cfg.href = this.href;
32864 var cn = cfg.cn[1].cn;
32866 if(this.title.length){
32869 cls: 'masonry-brick-title',
32874 if(this.html.length){
32877 cls: 'masonry-brick-text',
32882 if (!this.title.length && !this.html.length) {
32883 cfg.cn[1].cls += ' hide';
32886 if(this.bgimage.length){
32889 cls: 'masonry-brick-image-view',
32894 if(this.videourl.length){
32895 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32896 // youtube support only?
32899 cls: 'masonry-brick-image-view',
32902 allowfullscreen : true
32910 getSplitAutoCreate : function()
32912 var cls = 'masonry-brick masonry-brick-split';
32914 if(this.href.length){
32915 cls += ' masonry-brick-link';
32918 if(this.bgimage.length){
32919 cls += ' masonry-brick-image';
32923 cls += ' masonry-' + this.size + '-brick';
32926 switch (this.placetitle) {
32928 cls += ' masonry-center-title';
32931 cls += ' masonry-bottom-title';
32934 if(!this.bgimage.length){
32935 cls += ' masonry-center-title';
32938 if(this.bgimage.length){
32939 cls += ' masonry-bottom-title';
32945 cls += ' ' + this.cls;
32949 tag: (this.href.length) ? 'a' : 'div',
32954 cls: 'masonry-brick-split-head',
32958 cls: 'masonry-brick-paragraph',
32965 cls: 'masonry-brick-split-body',
32971 if(this.href.length){
32972 cfg.href = this.href;
32975 if(this.title.length){
32976 cfg.cn[0].cn[0].cn.push({
32978 cls: 'masonry-brick-title',
32983 if(this.html.length){
32984 cfg.cn[1].cn.push({
32986 cls: 'masonry-brick-text',
32991 if(this.bgimage.length){
32992 cfg.cn[0].cn.push({
32994 cls: 'masonry-brick-image-view',
32999 if(this.videourl.length){
33000 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33001 // youtube support only?
33002 cfg.cn[0].cn.cn.push({
33004 cls: 'masonry-brick-image-view',
33007 allowfullscreen : true
33014 initEvents: function()
33016 switch (this.size) {
33049 this.el.on('touchstart', this.onTouchStart, this);
33050 this.el.on('touchmove', this.onTouchMove, this);
33051 this.el.on('touchend', this.onTouchEnd, this);
33052 this.el.on('contextmenu', this.onContextMenu, this);
33054 this.el.on('mouseenter' ,this.enter, this);
33055 this.el.on('mouseleave', this.leave, this);
33056 this.el.on('click', this.onClick, this);
33059 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33060 this.parent().bricks.push(this);
33065 onClick: function(e, el)
33067 var time = this.endTimer - this.startTimer;
33068 // Roo.log(e.preventDefault());
33071 e.preventDefault();
33076 if(!this.preventDefault){
33080 e.preventDefault();
33082 if (this.activeClass != '') {
33083 this.selectBrick();
33086 this.fireEvent('click', this, e);
33089 enter: function(e, el)
33091 e.preventDefault();
33093 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33097 if(this.bgimage.length && this.html.length){
33098 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33102 leave: function(e, el)
33104 e.preventDefault();
33106 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33110 if(this.bgimage.length && this.html.length){
33111 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33115 onTouchStart: function(e, el)
33117 // e.preventDefault();
33119 this.touchmoved = false;
33121 if(!this.isFitContainer){
33125 if(!this.bgimage.length || !this.html.length){
33129 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33131 this.timer = new Date().getTime();
33135 onTouchMove: function(e, el)
33137 this.touchmoved = true;
33140 onContextMenu : function(e,el)
33142 e.preventDefault();
33143 e.stopPropagation();
33147 onTouchEnd: function(e, el)
33149 // e.preventDefault();
33151 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33158 if(!this.bgimage.length || !this.html.length){
33160 if(this.href.length){
33161 window.location.href = this.href;
33167 if(!this.isFitContainer){
33171 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33173 window.location.href = this.href;
33176 //selection on single brick only
33177 selectBrick : function() {
33179 if (!this.parentId) {
33183 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33184 var index = m.selectedBrick.indexOf(this.id);
33187 m.selectedBrick.splice(index,1);
33188 this.el.removeClass(this.activeClass);
33192 for(var i = 0; i < m.selectedBrick.length; i++) {
33193 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33194 b.el.removeClass(b.activeClass);
33197 m.selectedBrick = [];
33199 m.selectedBrick.push(this.id);
33200 this.el.addClass(this.activeClass);
33204 isSelected : function(){
33205 return this.el.hasClass(this.activeClass);
33210 Roo.apply(Roo.bootstrap.MasonryBrick, {
33213 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33215 * register a Masonry Brick
33216 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33219 register : function(brick)
33221 //this.groups[brick.id] = brick;
33222 this.groups.add(brick.id, brick);
33225 * fetch a masonry brick based on the masonry brick ID
33226 * @param {string} the masonry brick to add
33227 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33230 get: function(brick_id)
33232 // if (typeof(this.groups[brick_id]) == 'undefined') {
33235 // return this.groups[brick_id] ;
33237 if(this.groups.key(brick_id)) {
33238 return this.groups.key(brick_id);
33256 * @class Roo.bootstrap.Brick
33257 * @extends Roo.bootstrap.Component
33258 * Bootstrap Brick class
33261 * Create a new Brick
33262 * @param {Object} config The config object
33265 Roo.bootstrap.Brick = function(config){
33266 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33272 * When a Brick is click
33273 * @param {Roo.bootstrap.Brick} this
33274 * @param {Roo.EventObject} e
33280 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33283 * @cfg {String} title
33287 * @cfg {String} html
33291 * @cfg {String} bgimage
33295 * @cfg {String} cls
33299 * @cfg {String} href
33303 * @cfg {String} video
33307 * @cfg {Boolean} square
33311 getAutoCreate : function()
33313 var cls = 'roo-brick';
33315 if(this.href.length){
33316 cls += ' roo-brick-link';
33319 if(this.bgimage.length){
33320 cls += ' roo-brick-image';
33323 if(!this.html.length && !this.bgimage.length){
33324 cls += ' roo-brick-center-title';
33327 if(!this.html.length && this.bgimage.length){
33328 cls += ' roo-brick-bottom-title';
33332 cls += ' ' + this.cls;
33336 tag: (this.href.length) ? 'a' : 'div',
33341 cls: 'roo-brick-paragraph',
33347 if(this.href.length){
33348 cfg.href = this.href;
33351 var cn = cfg.cn[0].cn;
33353 if(this.title.length){
33356 cls: 'roo-brick-title',
33361 if(this.html.length){
33364 cls: 'roo-brick-text',
33371 if(this.bgimage.length){
33374 cls: 'roo-brick-image-view',
33382 initEvents: function()
33384 if(this.title.length || this.html.length){
33385 this.el.on('mouseenter' ,this.enter, this);
33386 this.el.on('mouseleave', this.leave, this);
33389 Roo.EventManager.onWindowResize(this.resize, this);
33391 if(this.bgimage.length){
33392 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33393 this.imageEl.on('load', this.onImageLoad, this);
33400 onImageLoad : function()
33405 resize : function()
33407 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33409 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33411 if(this.bgimage.length){
33412 var image = this.el.select('.roo-brick-image-view', true).first();
33414 image.setWidth(paragraph.getWidth());
33417 image.setHeight(paragraph.getWidth());
33420 this.el.setHeight(image.getHeight());
33421 paragraph.setHeight(image.getHeight());
33427 enter: function(e, el)
33429 e.preventDefault();
33431 if(this.bgimage.length){
33432 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33433 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33437 leave: function(e, el)
33439 e.preventDefault();
33441 if(this.bgimage.length){
33442 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33443 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33458 * @class Roo.bootstrap.NumberField
33459 * @extends Roo.bootstrap.Input
33460 * Bootstrap NumberField class
33466 * Create a new NumberField
33467 * @param {Object} config The config object
33470 Roo.bootstrap.NumberField = function(config){
33471 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33474 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33477 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33479 allowDecimals : true,
33481 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33483 decimalSeparator : ".",
33485 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33487 decimalPrecision : 2,
33489 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33491 allowNegative : true,
33494 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33498 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33500 minValue : Number.NEGATIVE_INFINITY,
33502 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33504 maxValue : Number.MAX_VALUE,
33506 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33508 minText : "The minimum value for this field is {0}",
33510 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33512 maxText : "The maximum value for this field is {0}",
33514 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33515 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33517 nanText : "{0} is not a valid number",
33519 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33521 thousandsDelimiter : false,
33523 * @cfg {String} valueAlign alignment of value
33525 valueAlign : "left",
33527 getAutoCreate : function()
33529 var hiddenInput = {
33533 cls: 'hidden-number-input'
33537 hiddenInput.name = this.name;
33542 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33544 this.name = hiddenInput.name;
33546 if(cfg.cn.length > 0) {
33547 cfg.cn.push(hiddenInput);
33554 initEvents : function()
33556 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33558 var allowed = "0123456789";
33560 if(this.allowDecimals){
33561 allowed += this.decimalSeparator;
33564 if(this.allowNegative){
33568 if(this.thousandsDelimiter) {
33572 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33574 var keyPress = function(e){
33576 var k = e.getKey();
33578 var c = e.getCharCode();
33581 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33582 allowed.indexOf(String.fromCharCode(c)) === -1
33588 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33592 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33597 this.el.on("keypress", keyPress, this);
33600 validateValue : function(value)
33603 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33607 var num = this.parseValue(value);
33610 this.markInvalid(String.format(this.nanText, value));
33614 if(num < this.minValue){
33615 this.markInvalid(String.format(this.minText, this.minValue));
33619 if(num > this.maxValue){
33620 this.markInvalid(String.format(this.maxText, this.maxValue));
33627 getValue : function()
33629 var v = this.hiddenEl().getValue();
33631 return this.fixPrecision(this.parseValue(v));
33634 parseValue : function(value)
33636 if(this.thousandsDelimiter) {
33638 r = new RegExp(",", "g");
33639 value = value.replace(r, "");
33642 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33643 return isNaN(value) ? '' : value;
33646 fixPrecision : function(value)
33648 if(this.thousandsDelimiter) {
33650 r = new RegExp(",", "g");
33651 value = value.replace(r, "");
33654 var nan = isNaN(value);
33656 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33657 return nan ? '' : value;
33659 return parseFloat(value).toFixed(this.decimalPrecision);
33662 setValue : function(v)
33664 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33670 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33672 this.inputEl().dom.value = (v == '') ? '' :
33673 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33675 if(!this.allowZero && v === '0') {
33676 this.hiddenEl().dom.value = '';
33677 this.inputEl().dom.value = '';
33684 decimalPrecisionFcn : function(v)
33686 return Math.floor(v);
33689 beforeBlur : function()
33691 var v = this.parseValue(this.getRawValue());
33693 if(v || v === 0 || v === ''){
33698 hiddenEl : function()
33700 return this.el.select('input.hidden-number-input',true).first();
33712 * @class Roo.bootstrap.DocumentSlider
33713 * @extends Roo.bootstrap.Component
33714 * Bootstrap DocumentSlider class
33717 * Create a new DocumentViewer
33718 * @param {Object} config The config object
33721 Roo.bootstrap.DocumentSlider = function(config){
33722 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33729 * Fire after initEvent
33730 * @param {Roo.bootstrap.DocumentSlider} this
33735 * Fire after update
33736 * @param {Roo.bootstrap.DocumentSlider} this
33742 * @param {Roo.bootstrap.DocumentSlider} this
33748 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33754 getAutoCreate : function()
33758 cls : 'roo-document-slider',
33762 cls : 'roo-document-slider-header',
33766 cls : 'roo-document-slider-header-title'
33772 cls : 'roo-document-slider-body',
33776 cls : 'roo-document-slider-prev',
33780 cls : 'fa fa-chevron-left'
33786 cls : 'roo-document-slider-thumb',
33790 cls : 'roo-document-slider-image'
33796 cls : 'roo-document-slider-next',
33800 cls : 'fa fa-chevron-right'
33812 initEvents : function()
33814 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33815 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33817 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33818 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33820 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33821 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33823 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33824 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33826 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33827 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33829 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33830 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33832 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33833 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33835 this.thumbEl.on('click', this.onClick, this);
33837 this.prevIndicator.on('click', this.prev, this);
33839 this.nextIndicator.on('click', this.next, this);
33843 initial : function()
33845 if(this.files.length){
33846 this.indicator = 1;
33850 this.fireEvent('initial', this);
33853 update : function()
33855 this.imageEl.attr('src', this.files[this.indicator - 1]);
33857 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33859 this.prevIndicator.show();
33861 if(this.indicator == 1){
33862 this.prevIndicator.hide();
33865 this.nextIndicator.show();
33867 if(this.indicator == this.files.length){
33868 this.nextIndicator.hide();
33871 this.thumbEl.scrollTo('top');
33873 this.fireEvent('update', this);
33876 onClick : function(e)
33878 e.preventDefault();
33880 this.fireEvent('click', this);
33885 e.preventDefault();
33887 this.indicator = Math.max(1, this.indicator - 1);
33894 e.preventDefault();
33896 this.indicator = Math.min(this.files.length, this.indicator + 1);
33910 * @class Roo.bootstrap.RadioSet
33911 * @extends Roo.bootstrap.Input
33912 * Bootstrap RadioSet class
33913 * @cfg {String} indicatorpos (left|right) default left
33914 * @cfg {Boolean} inline (true|false) inline the element (default true)
33915 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33917 * Create a new RadioSet
33918 * @param {Object} config The config object
33921 Roo.bootstrap.RadioSet = function(config){
33923 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33927 Roo.bootstrap.RadioSet.register(this);
33932 * Fires when the element is checked or unchecked.
33933 * @param {Roo.bootstrap.RadioSet} this This radio
33934 * @param {Roo.bootstrap.Radio} item The checked item
33939 * Fires when the element is click.
33940 * @param {Roo.bootstrap.RadioSet} this This radio set
33941 * @param {Roo.bootstrap.Radio} item The checked item
33942 * @param {Roo.EventObject} e The event object
33949 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33957 indicatorpos : 'left',
33959 getAutoCreate : function()
33963 cls : 'roo-radio-set-label',
33967 html : this.fieldLabel
33972 if(this.indicatorpos == 'left'){
33975 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33976 tooltip : 'This field is required'
33981 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33982 tooltip : 'This field is required'
33988 cls : 'roo-radio-set-items'
33991 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33993 if (align === 'left' && this.fieldLabel.length) {
33996 cls : "roo-radio-set-right",
34002 if(this.labelWidth > 12){
34003 label.style = "width: " + this.labelWidth + 'px';
34006 if(this.labelWidth < 13 && this.labelmd == 0){
34007 this.labelmd = this.labelWidth;
34010 if(this.labellg > 0){
34011 label.cls += ' col-lg-' + this.labellg;
34012 items.cls += ' col-lg-' + (12 - this.labellg);
34015 if(this.labelmd > 0){
34016 label.cls += ' col-md-' + this.labelmd;
34017 items.cls += ' col-md-' + (12 - this.labelmd);
34020 if(this.labelsm > 0){
34021 label.cls += ' col-sm-' + this.labelsm;
34022 items.cls += ' col-sm-' + (12 - this.labelsm);
34025 if(this.labelxs > 0){
34026 label.cls += ' col-xs-' + this.labelxs;
34027 items.cls += ' col-xs-' + (12 - this.labelxs);
34033 cls : 'roo-radio-set',
34037 cls : 'roo-radio-set-input',
34040 value : this.value ? this.value : ''
34047 if(this.weight.length){
34048 cfg.cls += ' roo-radio-' + this.weight;
34052 cfg.cls += ' roo-radio-set-inline';
34056 ['xs','sm','md','lg'].map(function(size){
34057 if (settings[size]) {
34058 cfg.cls += ' col-' + size + '-' + settings[size];
34066 initEvents : function()
34068 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34069 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34071 if(!this.fieldLabel.length){
34072 this.labelEl.hide();
34075 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34076 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34078 this.indicator = this.indicatorEl();
34080 if(this.indicator){
34081 this.indicator.addClass('invisible');
34084 this.originalValue = this.getValue();
34088 inputEl: function ()
34090 return this.el.select('.roo-radio-set-input', true).first();
34093 getChildContainer : function()
34095 return this.itemsEl;
34098 register : function(item)
34100 this.radioes.push(item);
34104 validate : function()
34106 if(this.getVisibilityEl().hasClass('hidden')){
34112 Roo.each(this.radioes, function(i){
34121 if(this.allowBlank) {
34125 if(this.disabled || valid){
34130 this.markInvalid();
34135 markValid : function()
34137 if(this.labelEl.isVisible(true)){
34138 this.indicatorEl().removeClass('visible');
34139 this.indicatorEl().addClass('invisible');
34142 this.el.removeClass([this.invalidClass, this.validClass]);
34143 this.el.addClass(this.validClass);
34145 this.fireEvent('valid', this);
34148 markInvalid : function(msg)
34150 if(this.allowBlank || this.disabled){
34154 if(this.labelEl.isVisible(true)){
34155 this.indicatorEl().removeClass('invisible');
34156 this.indicatorEl().addClass('visible');
34159 this.el.removeClass([this.invalidClass, this.validClass]);
34160 this.el.addClass(this.invalidClass);
34162 this.fireEvent('invalid', this, msg);
34166 setValue : function(v, suppressEvent)
34168 if(this.value === v){
34175 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34178 Roo.each(this.radioes, function(i){
34180 i.el.removeClass('checked');
34183 Roo.each(this.radioes, function(i){
34185 if(i.value === v || i.value.toString() === v.toString()){
34187 i.el.addClass('checked');
34189 if(suppressEvent !== true){
34190 this.fireEvent('check', this, i);
34201 clearInvalid : function(){
34203 if(!this.el || this.preventMark){
34207 this.el.removeClass([this.invalidClass]);
34209 this.fireEvent('valid', this);
34214 Roo.apply(Roo.bootstrap.RadioSet, {
34218 register : function(set)
34220 this.groups[set.name] = set;
34223 get: function(name)
34225 if (typeof(this.groups[name]) == 'undefined') {
34229 return this.groups[name] ;
34235 * Ext JS Library 1.1.1
34236 * Copyright(c) 2006-2007, Ext JS, LLC.
34238 * Originally Released Under LGPL - original licence link has changed is not relivant.
34241 * <script type="text/javascript">
34246 * @class Roo.bootstrap.SplitBar
34247 * @extends Roo.util.Observable
34248 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34252 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34253 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34254 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34255 split.minSize = 100;
34256 split.maxSize = 600;
34257 split.animate = true;
34258 split.on('moved', splitterMoved);
34261 * Create a new SplitBar
34262 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34263 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34264 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34265 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34266 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34267 position of the SplitBar).
34269 Roo.bootstrap.SplitBar = function(cfg){
34274 // dragElement : elm
34275 // resizingElement: el,
34277 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34278 // placement : Roo.bootstrap.SplitBar.LEFT ,
34279 // existingProxy ???
34282 this.el = Roo.get(cfg.dragElement, true);
34283 this.el.dom.unselectable = "on";
34285 this.resizingEl = Roo.get(cfg.resizingElement, true);
34289 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34290 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34293 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34296 * The minimum size of the resizing element. (Defaults to 0)
34302 * The maximum size of the resizing element. (Defaults to 2000)
34305 this.maxSize = 2000;
34308 * Whether to animate the transition to the new size
34311 this.animate = false;
34314 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34317 this.useShim = false;
34322 if(!cfg.existingProxy){
34324 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34326 this.proxy = Roo.get(cfg.existingProxy).dom;
34329 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34332 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34335 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34338 this.dragSpecs = {};
34341 * @private The adapter to use to positon and resize elements
34343 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34344 this.adapter.init(this);
34346 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34348 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34349 this.el.addClass("roo-splitbar-h");
34352 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34353 this.el.addClass("roo-splitbar-v");
34359 * Fires when the splitter is moved (alias for {@link #event-moved})
34360 * @param {Roo.bootstrap.SplitBar} this
34361 * @param {Number} newSize the new width or height
34366 * Fires when the splitter is moved
34367 * @param {Roo.bootstrap.SplitBar} this
34368 * @param {Number} newSize the new width or height
34372 * @event beforeresize
34373 * Fires before the splitter is dragged
34374 * @param {Roo.bootstrap.SplitBar} this
34376 "beforeresize" : true,
34378 "beforeapply" : true
34381 Roo.util.Observable.call(this);
34384 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34385 onStartProxyDrag : function(x, y){
34386 this.fireEvent("beforeresize", this);
34388 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34390 o.enableDisplayMode("block");
34391 // all splitbars share the same overlay
34392 Roo.bootstrap.SplitBar.prototype.overlay = o;
34394 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34395 this.overlay.show();
34396 Roo.get(this.proxy).setDisplayed("block");
34397 var size = this.adapter.getElementSize(this);
34398 this.activeMinSize = this.getMinimumSize();;
34399 this.activeMaxSize = this.getMaximumSize();;
34400 var c1 = size - this.activeMinSize;
34401 var c2 = Math.max(this.activeMaxSize - size, 0);
34402 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34403 this.dd.resetConstraints();
34404 this.dd.setXConstraint(
34405 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34406 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34408 this.dd.setYConstraint(0, 0);
34410 this.dd.resetConstraints();
34411 this.dd.setXConstraint(0, 0);
34412 this.dd.setYConstraint(
34413 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34414 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34417 this.dragSpecs.startSize = size;
34418 this.dragSpecs.startPoint = [x, y];
34419 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34423 * @private Called after the drag operation by the DDProxy
34425 onEndProxyDrag : function(e){
34426 Roo.get(this.proxy).setDisplayed(false);
34427 var endPoint = Roo.lib.Event.getXY(e);
34429 this.overlay.hide();
34432 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34433 newSize = this.dragSpecs.startSize +
34434 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34435 endPoint[0] - this.dragSpecs.startPoint[0] :
34436 this.dragSpecs.startPoint[0] - endPoint[0]
34439 newSize = this.dragSpecs.startSize +
34440 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34441 endPoint[1] - this.dragSpecs.startPoint[1] :
34442 this.dragSpecs.startPoint[1] - endPoint[1]
34445 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34446 if(newSize != this.dragSpecs.startSize){
34447 if(this.fireEvent('beforeapply', this, newSize) !== false){
34448 this.adapter.setElementSize(this, newSize);
34449 this.fireEvent("moved", this, newSize);
34450 this.fireEvent("resize", this, newSize);
34456 * Get the adapter this SplitBar uses
34457 * @return The adapter object
34459 getAdapter : function(){
34460 return this.adapter;
34464 * Set the adapter this SplitBar uses
34465 * @param {Object} adapter A SplitBar adapter object
34467 setAdapter : function(adapter){
34468 this.adapter = adapter;
34469 this.adapter.init(this);
34473 * Gets the minimum size for the resizing element
34474 * @return {Number} The minimum size
34476 getMinimumSize : function(){
34477 return this.minSize;
34481 * Sets the minimum size for the resizing element
34482 * @param {Number} minSize The minimum size
34484 setMinimumSize : function(minSize){
34485 this.minSize = minSize;
34489 * Gets the maximum size for the resizing element
34490 * @return {Number} The maximum size
34492 getMaximumSize : function(){
34493 return this.maxSize;
34497 * Sets the maximum size for the resizing element
34498 * @param {Number} maxSize The maximum size
34500 setMaximumSize : function(maxSize){
34501 this.maxSize = maxSize;
34505 * Sets the initialize size for the resizing element
34506 * @param {Number} size The initial size
34508 setCurrentSize : function(size){
34509 var oldAnimate = this.animate;
34510 this.animate = false;
34511 this.adapter.setElementSize(this, size);
34512 this.animate = oldAnimate;
34516 * Destroy this splitbar.
34517 * @param {Boolean} removeEl True to remove the element
34519 destroy : function(removeEl){
34521 this.shim.remove();
34524 this.proxy.parentNode.removeChild(this.proxy);
34532 * @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.
34534 Roo.bootstrap.SplitBar.createProxy = function(dir){
34535 var proxy = new Roo.Element(document.createElement("div"));
34536 proxy.unselectable();
34537 var cls = 'roo-splitbar-proxy';
34538 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34539 document.body.appendChild(proxy.dom);
34544 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34545 * Default Adapter. It assumes the splitter and resizing element are not positioned
34546 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34548 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34551 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34552 // do nothing for now
34553 init : function(s){
34557 * Called before drag operations to get the current size of the resizing element.
34558 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34560 getElementSize : function(s){
34561 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34562 return s.resizingEl.getWidth();
34564 return s.resizingEl.getHeight();
34569 * Called after drag operations to set the size of the resizing element.
34570 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34571 * @param {Number} newSize The new size to set
34572 * @param {Function} onComplete A function to be invoked when resizing is complete
34574 setElementSize : function(s, newSize, onComplete){
34575 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34577 s.resizingEl.setWidth(newSize);
34579 onComplete(s, newSize);
34582 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34587 s.resizingEl.setHeight(newSize);
34589 onComplete(s, newSize);
34592 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34599 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34600 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34601 * Adapter that moves the splitter element to align with the resized sizing element.
34602 * Used with an absolute positioned SplitBar.
34603 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34604 * document.body, make sure you assign an id to the body element.
34606 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34607 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34608 this.container = Roo.get(container);
34611 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34612 init : function(s){
34613 this.basic.init(s);
34616 getElementSize : function(s){
34617 return this.basic.getElementSize(s);
34620 setElementSize : function(s, newSize, onComplete){
34621 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34624 moveSplitter : function(s){
34625 var yes = Roo.bootstrap.SplitBar;
34626 switch(s.placement){
34628 s.el.setX(s.resizingEl.getRight());
34631 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34634 s.el.setY(s.resizingEl.getBottom());
34637 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34644 * Orientation constant - Create a vertical SplitBar
34648 Roo.bootstrap.SplitBar.VERTICAL = 1;
34651 * Orientation constant - Create a horizontal SplitBar
34655 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34658 * Placement constant - The resizing element is to the left of the splitter element
34662 Roo.bootstrap.SplitBar.LEFT = 1;
34665 * Placement constant - The resizing element is to the right of the splitter element
34669 Roo.bootstrap.SplitBar.RIGHT = 2;
34672 * Placement constant - The resizing element is positioned above the splitter element
34676 Roo.bootstrap.SplitBar.TOP = 3;
34679 * Placement constant - The resizing element is positioned under splitter element
34683 Roo.bootstrap.SplitBar.BOTTOM = 4;
34684 Roo.namespace("Roo.bootstrap.layout");/*
34686 * Ext JS Library 1.1.1
34687 * Copyright(c) 2006-2007, Ext JS, LLC.
34689 * Originally Released Under LGPL - original licence link has changed is not relivant.
34692 * <script type="text/javascript">
34696 * @class Roo.bootstrap.layout.Manager
34697 * @extends Roo.bootstrap.Component
34698 * Base class for layout managers.
34700 Roo.bootstrap.layout.Manager = function(config)
34702 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34708 /** false to disable window resize monitoring @type Boolean */
34709 this.monitorWindowResize = true;
34714 * Fires when a layout is performed.
34715 * @param {Roo.LayoutManager} this
34719 * @event regionresized
34720 * Fires when the user resizes a region.
34721 * @param {Roo.LayoutRegion} region The resized region
34722 * @param {Number} newSize The new size (width for east/west, height for north/south)
34724 "regionresized" : true,
34726 * @event regioncollapsed
34727 * Fires when a region is collapsed.
34728 * @param {Roo.LayoutRegion} region The collapsed region
34730 "regioncollapsed" : true,
34732 * @event regionexpanded
34733 * Fires when a region is expanded.
34734 * @param {Roo.LayoutRegion} region The expanded region
34736 "regionexpanded" : true
34738 this.updating = false;
34741 this.el = Roo.get(config.el);
34747 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34752 monitorWindowResize : true,
34758 onRender : function(ct, position)
34761 this.el = Roo.get(ct);
34764 //this.fireEvent('render',this);
34768 initEvents: function()
34772 // ie scrollbar fix
34773 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34774 document.body.scroll = "no";
34775 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34776 this.el.position('relative');
34778 this.id = this.el.id;
34779 this.el.addClass("roo-layout-container");
34780 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34781 if(this.el.dom != document.body ) {
34782 this.el.on('resize', this.layout,this);
34783 this.el.on('show', this.layout,this);
34789 * Returns true if this layout is currently being updated
34790 * @return {Boolean}
34792 isUpdating : function(){
34793 return this.updating;
34797 * Suspend the LayoutManager from doing auto-layouts while
34798 * making multiple add or remove calls
34800 beginUpdate : function(){
34801 this.updating = true;
34805 * Restore auto-layouts and optionally disable the manager from performing a layout
34806 * @param {Boolean} noLayout true to disable a layout update
34808 endUpdate : function(noLayout){
34809 this.updating = false;
34815 layout: function(){
34819 onRegionResized : function(region, newSize){
34820 this.fireEvent("regionresized", region, newSize);
34824 onRegionCollapsed : function(region){
34825 this.fireEvent("regioncollapsed", region);
34828 onRegionExpanded : function(region){
34829 this.fireEvent("regionexpanded", region);
34833 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34834 * performs box-model adjustments.
34835 * @return {Object} The size as an object {width: (the width), height: (the height)}
34837 getViewSize : function()
34840 if(this.el.dom != document.body){
34841 size = this.el.getSize();
34843 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34845 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34846 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34851 * Returns the Element this layout is bound to.
34852 * @return {Roo.Element}
34854 getEl : function(){
34859 * Returns the specified region.
34860 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34861 * @return {Roo.LayoutRegion}
34863 getRegion : function(target){
34864 return this.regions[target.toLowerCase()];
34867 onWindowResize : function(){
34868 if(this.monitorWindowResize){
34875 * Ext JS Library 1.1.1
34876 * Copyright(c) 2006-2007, Ext JS, LLC.
34878 * Originally Released Under LGPL - original licence link has changed is not relivant.
34881 * <script type="text/javascript">
34884 * @class Roo.bootstrap.layout.Border
34885 * @extends Roo.bootstrap.layout.Manager
34886 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34887 * please see: examples/bootstrap/nested.html<br><br>
34889 <b>The container the layout is rendered into can be either the body element or any other element.
34890 If it is not the body element, the container needs to either be an absolute positioned element,
34891 or you will need to add "position:relative" to the css of the container. You will also need to specify
34892 the container size if it is not the body element.</b>
34895 * Create a new Border
34896 * @param {Object} config Configuration options
34898 Roo.bootstrap.layout.Border = function(config){
34899 config = config || {};
34900 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34904 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34905 if(config[region]){
34906 config[region].region = region;
34907 this.addRegion(config[region]);
34913 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34915 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34917 * Creates and adds a new region if it doesn't already exist.
34918 * @param {String} target The target region key (north, south, east, west or center).
34919 * @param {Object} config The regions config object
34920 * @return {BorderLayoutRegion} The new region
34922 addRegion : function(config)
34924 if(!this.regions[config.region]){
34925 var r = this.factory(config);
34926 this.bindRegion(r);
34928 return this.regions[config.region];
34932 bindRegion : function(r){
34933 this.regions[r.config.region] = r;
34935 r.on("visibilitychange", this.layout, this);
34936 r.on("paneladded", this.layout, this);
34937 r.on("panelremoved", this.layout, this);
34938 r.on("invalidated", this.layout, this);
34939 r.on("resized", this.onRegionResized, this);
34940 r.on("collapsed", this.onRegionCollapsed, this);
34941 r.on("expanded", this.onRegionExpanded, this);
34945 * Performs a layout update.
34947 layout : function()
34949 if(this.updating) {
34953 // render all the rebions if they have not been done alreayd?
34954 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34955 if(this.regions[region] && !this.regions[region].bodyEl){
34956 this.regions[region].onRender(this.el)
34960 var size = this.getViewSize();
34961 var w = size.width;
34962 var h = size.height;
34967 //var x = 0, y = 0;
34969 var rs = this.regions;
34970 var north = rs["north"];
34971 var south = rs["south"];
34972 var west = rs["west"];
34973 var east = rs["east"];
34974 var center = rs["center"];
34975 //if(this.hideOnLayout){ // not supported anymore
34976 //c.el.setStyle("display", "none");
34978 if(north && north.isVisible()){
34979 var b = north.getBox();
34980 var m = north.getMargins();
34981 b.width = w - (m.left+m.right);
34984 centerY = b.height + b.y + m.bottom;
34985 centerH -= centerY;
34986 north.updateBox(this.safeBox(b));
34988 if(south && south.isVisible()){
34989 var b = south.getBox();
34990 var m = south.getMargins();
34991 b.width = w - (m.left+m.right);
34993 var totalHeight = (b.height + m.top + m.bottom);
34994 b.y = h - totalHeight + m.top;
34995 centerH -= totalHeight;
34996 south.updateBox(this.safeBox(b));
34998 if(west && west.isVisible()){
34999 var b = west.getBox();
35000 var m = west.getMargins();
35001 b.height = centerH - (m.top+m.bottom);
35003 b.y = centerY + m.top;
35004 var totalWidth = (b.width + m.left + m.right);
35005 centerX += totalWidth;
35006 centerW -= totalWidth;
35007 west.updateBox(this.safeBox(b));
35009 if(east && east.isVisible()){
35010 var b = east.getBox();
35011 var m = east.getMargins();
35012 b.height = centerH - (m.top+m.bottom);
35013 var totalWidth = (b.width + m.left + m.right);
35014 b.x = w - totalWidth + m.left;
35015 b.y = centerY + m.top;
35016 centerW -= totalWidth;
35017 east.updateBox(this.safeBox(b));
35020 var m = center.getMargins();
35022 x: centerX + m.left,
35023 y: centerY + m.top,
35024 width: centerW - (m.left+m.right),
35025 height: centerH - (m.top+m.bottom)
35027 //if(this.hideOnLayout){
35028 //center.el.setStyle("display", "block");
35030 center.updateBox(this.safeBox(centerBox));
35033 this.fireEvent("layout", this);
35037 safeBox : function(box){
35038 box.width = Math.max(0, box.width);
35039 box.height = Math.max(0, box.height);
35044 * Adds a ContentPanel (or subclass) to this layout.
35045 * @param {String} target The target region key (north, south, east, west or center).
35046 * @param {Roo.ContentPanel} panel The panel to add
35047 * @return {Roo.ContentPanel} The added panel
35049 add : function(target, panel){
35051 target = target.toLowerCase();
35052 return this.regions[target].add(panel);
35056 * Remove a ContentPanel (or subclass) to this layout.
35057 * @param {String} target The target region key (north, south, east, west or center).
35058 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35059 * @return {Roo.ContentPanel} The removed panel
35061 remove : function(target, panel){
35062 target = target.toLowerCase();
35063 return this.regions[target].remove(panel);
35067 * Searches all regions for a panel with the specified id
35068 * @param {String} panelId
35069 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35071 findPanel : function(panelId){
35072 var rs = this.regions;
35073 for(var target in rs){
35074 if(typeof rs[target] != "function"){
35075 var p = rs[target].getPanel(panelId);
35085 * Searches all regions for a panel with the specified id and activates (shows) it.
35086 * @param {String/ContentPanel} panelId The panels id or the panel itself
35087 * @return {Roo.ContentPanel} The shown panel or null
35089 showPanel : function(panelId) {
35090 var rs = this.regions;
35091 for(var target in rs){
35092 var r = rs[target];
35093 if(typeof r != "function"){
35094 if(r.hasPanel(panelId)){
35095 return r.showPanel(panelId);
35103 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35104 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35107 restoreState : function(provider){
35109 provider = Roo.state.Manager;
35111 var sm = new Roo.LayoutStateManager();
35112 sm.init(this, provider);
35118 * Adds a xtype elements to the layout.
35122 xtype : 'ContentPanel',
35129 xtype : 'NestedLayoutPanel',
35135 items : [ ... list of content panels or nested layout panels.. ]
35139 * @param {Object} cfg Xtype definition of item to add.
35141 addxtype : function(cfg)
35143 // basically accepts a pannel...
35144 // can accept a layout region..!?!?
35145 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35148 // theory? children can only be panels??
35150 //if (!cfg.xtype.match(/Panel$/)) {
35155 if (typeof(cfg.region) == 'undefined') {
35156 Roo.log("Failed to add Panel, region was not set");
35160 var region = cfg.region;
35166 xitems = cfg.items;
35173 case 'Content': // ContentPanel (el, cfg)
35174 case 'Scroll': // ContentPanel (el, cfg)
35176 cfg.autoCreate = true;
35177 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35179 // var el = this.el.createChild();
35180 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35183 this.add(region, ret);
35187 case 'TreePanel': // our new panel!
35188 cfg.el = this.el.createChild();
35189 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35190 this.add(region, ret);
35195 // create a new Layout (which is a Border Layout...
35197 var clayout = cfg.layout;
35198 clayout.el = this.el.createChild();
35199 clayout.items = clayout.items || [];
35203 // replace this exitems with the clayout ones..
35204 xitems = clayout.items;
35206 // force background off if it's in center...
35207 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35208 cfg.background = false;
35210 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35213 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35214 //console.log('adding nested layout panel ' + cfg.toSource());
35215 this.add(region, ret);
35216 nb = {}; /// find first...
35221 // needs grid and region
35223 //var el = this.getRegion(region).el.createChild();
35225 *var el = this.el.createChild();
35226 // create the grid first...
35227 cfg.grid.container = el;
35228 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35231 if (region == 'center' && this.active ) {
35232 cfg.background = false;
35235 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35237 this.add(region, ret);
35239 if (cfg.background) {
35240 // render grid on panel activation (if panel background)
35241 ret.on('activate', function(gp) {
35242 if (!gp.grid.rendered) {
35243 // gp.grid.render(el);
35247 // cfg.grid.render(el);
35253 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35254 // it was the old xcomponent building that caused this before.
35255 // espeically if border is the top element in the tree.
35265 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35267 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35268 this.add(region, ret);
35272 throw "Can not add '" + cfg.xtype + "' to Border";
35278 this.beginUpdate();
35282 Roo.each(xitems, function(i) {
35283 region = nb && i.region ? i.region : false;
35285 var add = ret.addxtype(i);
35288 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35289 if (!i.background) {
35290 abn[region] = nb[region] ;
35297 // make the last non-background panel active..
35298 //if (nb) { Roo.log(abn); }
35301 for(var r in abn) {
35302 region = this.getRegion(r);
35304 // tried using nb[r], but it does not work..
35306 region.showPanel(abn[r]);
35317 factory : function(cfg)
35320 var validRegions = Roo.bootstrap.layout.Border.regions;
35322 var target = cfg.region;
35325 var r = Roo.bootstrap.layout;
35329 return new r.North(cfg);
35331 return new r.South(cfg);
35333 return new r.East(cfg);
35335 return new r.West(cfg);
35337 return new r.Center(cfg);
35339 throw 'Layout region "'+target+'" not supported.';
35346 * Ext JS Library 1.1.1
35347 * Copyright(c) 2006-2007, Ext JS, LLC.
35349 * Originally Released Under LGPL - original licence link has changed is not relivant.
35352 * <script type="text/javascript">
35356 * @class Roo.bootstrap.layout.Basic
35357 * @extends Roo.util.Observable
35358 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35359 * and does not have a titlebar, tabs or any other features. All it does is size and position
35360 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35361 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35362 * @cfg {string} region the region that it inhabits..
35363 * @cfg {bool} skipConfig skip config?
35367 Roo.bootstrap.layout.Basic = function(config){
35369 this.mgr = config.mgr;
35371 this.position = config.region;
35373 var skipConfig = config.skipConfig;
35377 * @scope Roo.BasicLayoutRegion
35381 * @event beforeremove
35382 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35383 * @param {Roo.LayoutRegion} this
35384 * @param {Roo.ContentPanel} panel The panel
35385 * @param {Object} e The cancel event object
35387 "beforeremove" : true,
35389 * @event invalidated
35390 * Fires when the layout for this region is changed.
35391 * @param {Roo.LayoutRegion} this
35393 "invalidated" : true,
35395 * @event visibilitychange
35396 * Fires when this region is shown or hidden
35397 * @param {Roo.LayoutRegion} this
35398 * @param {Boolean} visibility true or false
35400 "visibilitychange" : true,
35402 * @event paneladded
35403 * Fires when a panel is added.
35404 * @param {Roo.LayoutRegion} this
35405 * @param {Roo.ContentPanel} panel The panel
35407 "paneladded" : true,
35409 * @event panelremoved
35410 * Fires when a panel is removed.
35411 * @param {Roo.LayoutRegion} this
35412 * @param {Roo.ContentPanel} panel The panel
35414 "panelremoved" : true,
35416 * @event beforecollapse
35417 * Fires when this region before collapse.
35418 * @param {Roo.LayoutRegion} this
35420 "beforecollapse" : true,
35423 * Fires when this region is collapsed.
35424 * @param {Roo.LayoutRegion} this
35426 "collapsed" : true,
35429 * Fires when this region is expanded.
35430 * @param {Roo.LayoutRegion} this
35435 * Fires when this region is slid into view.
35436 * @param {Roo.LayoutRegion} this
35438 "slideshow" : true,
35441 * Fires when this region slides out of view.
35442 * @param {Roo.LayoutRegion} this
35444 "slidehide" : true,
35446 * @event panelactivated
35447 * Fires when a panel is activated.
35448 * @param {Roo.LayoutRegion} this
35449 * @param {Roo.ContentPanel} panel The activated panel
35451 "panelactivated" : true,
35454 * Fires when the user resizes this region.
35455 * @param {Roo.LayoutRegion} this
35456 * @param {Number} newSize The new size (width for east/west, height for north/south)
35460 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35461 this.panels = new Roo.util.MixedCollection();
35462 this.panels.getKey = this.getPanelId.createDelegate(this);
35464 this.activePanel = null;
35465 // ensure listeners are added...
35467 if (config.listeners || config.events) {
35468 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35469 listeners : config.listeners || {},
35470 events : config.events || {}
35474 if(skipConfig !== true){
35475 this.applyConfig(config);
35479 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35481 getPanelId : function(p){
35485 applyConfig : function(config){
35486 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35487 this.config = config;
35492 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35493 * the width, for horizontal (north, south) the height.
35494 * @param {Number} newSize The new width or height
35496 resizeTo : function(newSize){
35497 var el = this.el ? this.el :
35498 (this.activePanel ? this.activePanel.getEl() : null);
35500 switch(this.position){
35503 el.setWidth(newSize);
35504 this.fireEvent("resized", this, newSize);
35508 el.setHeight(newSize);
35509 this.fireEvent("resized", this, newSize);
35515 getBox : function(){
35516 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35519 getMargins : function(){
35520 return this.margins;
35523 updateBox : function(box){
35525 var el = this.activePanel.getEl();
35526 el.dom.style.left = box.x + "px";
35527 el.dom.style.top = box.y + "px";
35528 this.activePanel.setSize(box.width, box.height);
35532 * Returns the container element for this region.
35533 * @return {Roo.Element}
35535 getEl : function(){
35536 return this.activePanel;
35540 * Returns true if this region is currently visible.
35541 * @return {Boolean}
35543 isVisible : function(){
35544 return this.activePanel ? true : false;
35547 setActivePanel : function(panel){
35548 panel = this.getPanel(panel);
35549 if(this.activePanel && this.activePanel != panel){
35550 this.activePanel.setActiveState(false);
35551 this.activePanel.getEl().setLeftTop(-10000,-10000);
35553 this.activePanel = panel;
35554 panel.setActiveState(true);
35556 panel.setSize(this.box.width, this.box.height);
35558 this.fireEvent("panelactivated", this, panel);
35559 this.fireEvent("invalidated");
35563 * Show the specified panel.
35564 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35565 * @return {Roo.ContentPanel} The shown panel or null
35567 showPanel : function(panel){
35568 panel = this.getPanel(panel);
35570 this.setActivePanel(panel);
35576 * Get the active panel for this region.
35577 * @return {Roo.ContentPanel} The active panel or null
35579 getActivePanel : function(){
35580 return this.activePanel;
35584 * Add the passed ContentPanel(s)
35585 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35586 * @return {Roo.ContentPanel} The panel added (if only one was added)
35588 add : function(panel){
35589 if(arguments.length > 1){
35590 for(var i = 0, len = arguments.length; i < len; i++) {
35591 this.add(arguments[i]);
35595 if(this.hasPanel(panel)){
35596 this.showPanel(panel);
35599 var el = panel.getEl();
35600 if(el.dom.parentNode != this.mgr.el.dom){
35601 this.mgr.el.dom.appendChild(el.dom);
35603 if(panel.setRegion){
35604 panel.setRegion(this);
35606 this.panels.add(panel);
35607 el.setStyle("position", "absolute");
35608 if(!panel.background){
35609 this.setActivePanel(panel);
35610 if(this.config.initialSize && this.panels.getCount()==1){
35611 this.resizeTo(this.config.initialSize);
35614 this.fireEvent("paneladded", this, panel);
35619 * Returns true if the panel is in this region.
35620 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35621 * @return {Boolean}
35623 hasPanel : function(panel){
35624 if(typeof panel == "object"){ // must be panel obj
35625 panel = panel.getId();
35627 return this.getPanel(panel) ? true : false;
35631 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35632 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35633 * @param {Boolean} preservePanel Overrides the config preservePanel option
35634 * @return {Roo.ContentPanel} The panel that was removed
35636 remove : function(panel, preservePanel){
35637 panel = this.getPanel(panel);
35642 this.fireEvent("beforeremove", this, panel, e);
35643 if(e.cancel === true){
35646 var panelId = panel.getId();
35647 this.panels.removeKey(panelId);
35652 * Returns the panel specified or null if it's not in this region.
35653 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35654 * @return {Roo.ContentPanel}
35656 getPanel : function(id){
35657 if(typeof id == "object"){ // must be panel obj
35660 return this.panels.get(id);
35664 * Returns this regions position (north/south/east/west/center).
35667 getPosition: function(){
35668 return this.position;
35672 * Ext JS Library 1.1.1
35673 * Copyright(c) 2006-2007, Ext JS, LLC.
35675 * Originally Released Under LGPL - original licence link has changed is not relivant.
35678 * <script type="text/javascript">
35682 * @class Roo.bootstrap.layout.Region
35683 * @extends Roo.bootstrap.layout.Basic
35684 * This class represents a region in a layout manager.
35686 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35687 * @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})
35688 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35689 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35690 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35691 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35692 * @cfg {String} title The title for the region (overrides panel titles)
35693 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35694 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35695 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35696 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35697 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35698 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35699 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35700 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35701 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35702 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35704 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35705 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35706 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35707 * @cfg {Number} width For East/West panels
35708 * @cfg {Number} height For North/South panels
35709 * @cfg {Boolean} split To show the splitter
35710 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35712 * @cfg {string} cls Extra CSS classes to add to region
35714 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35715 * @cfg {string} region the region that it inhabits..
35718 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35719 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35721 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35722 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35723 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35725 Roo.bootstrap.layout.Region = function(config)
35727 this.applyConfig(config);
35729 var mgr = config.mgr;
35730 var pos = config.region;
35731 config.skipConfig = true;
35732 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35735 this.onRender(mgr.el);
35738 this.visible = true;
35739 this.collapsed = false;
35740 this.unrendered_panels = [];
35743 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35745 position: '', // set by wrapper (eg. north/south etc..)
35746 unrendered_panels : null, // unrendered panels.
35747 createBody : function(){
35748 /** This region's body element
35749 * @type Roo.Element */
35750 this.bodyEl = this.el.createChild({
35752 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35756 onRender: function(ctr, pos)
35758 var dh = Roo.DomHelper;
35759 /** This region's container element
35760 * @type Roo.Element */
35761 this.el = dh.append(ctr.dom, {
35763 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35765 /** This region's title element
35766 * @type Roo.Element */
35768 this.titleEl = dh.append(this.el.dom,
35771 unselectable: "on",
35772 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35774 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35775 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35778 this.titleEl.enableDisplayMode();
35779 /** This region's title text element
35780 * @type HTMLElement */
35781 this.titleTextEl = this.titleEl.dom.firstChild;
35782 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35784 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35785 this.closeBtn.enableDisplayMode();
35786 this.closeBtn.on("click", this.closeClicked, this);
35787 this.closeBtn.hide();
35789 this.createBody(this.config);
35790 if(this.config.hideWhenEmpty){
35792 this.on("paneladded", this.validateVisibility, this);
35793 this.on("panelremoved", this.validateVisibility, this);
35795 if(this.autoScroll){
35796 this.bodyEl.setStyle("overflow", "auto");
35798 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35800 //if(c.titlebar !== false){
35801 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35802 this.titleEl.hide();
35804 this.titleEl.show();
35805 if(this.config.title){
35806 this.titleTextEl.innerHTML = this.config.title;
35810 if(this.config.collapsed){
35811 this.collapse(true);
35813 if(this.config.hidden){
35817 if (this.unrendered_panels && this.unrendered_panels.length) {
35818 for (var i =0;i< this.unrendered_panels.length; i++) {
35819 this.add(this.unrendered_panels[i]);
35821 this.unrendered_panels = null;
35827 applyConfig : function(c)
35830 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35831 var dh = Roo.DomHelper;
35832 if(c.titlebar !== false){
35833 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35834 this.collapseBtn.on("click", this.collapse, this);
35835 this.collapseBtn.enableDisplayMode();
35837 if(c.showPin === true || this.showPin){
35838 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35839 this.stickBtn.enableDisplayMode();
35840 this.stickBtn.on("click", this.expand, this);
35841 this.stickBtn.hide();
35846 /** This region's collapsed element
35847 * @type Roo.Element */
35850 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35851 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35854 if(c.floatable !== false){
35855 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35856 this.collapsedEl.on("click", this.collapseClick, this);
35859 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35860 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35861 id: "message", unselectable: "on", style:{"float":"left"}});
35862 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35864 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35865 this.expandBtn.on("click", this.expand, this);
35869 if(this.collapseBtn){
35870 this.collapseBtn.setVisible(c.collapsible == true);
35873 this.cmargins = c.cmargins || this.cmargins ||
35874 (this.position == "west" || this.position == "east" ?
35875 {top: 0, left: 2, right:2, bottom: 0} :
35876 {top: 2, left: 0, right:0, bottom: 2});
35878 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35881 this.bottomTabs = c.tabPosition != "top";
35883 this.autoScroll = c.autoScroll || false;
35888 this.duration = c.duration || .30;
35889 this.slideDuration = c.slideDuration || .45;
35894 * Returns true if this region is currently visible.
35895 * @return {Boolean}
35897 isVisible : function(){
35898 return this.visible;
35902 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35903 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35905 //setCollapsedTitle : function(title){
35906 // title = title || " ";
35907 // if(this.collapsedTitleTextEl){
35908 // this.collapsedTitleTextEl.innerHTML = title;
35912 getBox : function(){
35914 // if(!this.collapsed){
35915 b = this.el.getBox(false, true);
35917 // b = this.collapsedEl.getBox(false, true);
35922 getMargins : function(){
35923 return this.margins;
35924 //return this.collapsed ? this.cmargins : this.margins;
35927 highlight : function(){
35928 this.el.addClass("x-layout-panel-dragover");
35931 unhighlight : function(){
35932 this.el.removeClass("x-layout-panel-dragover");
35935 updateBox : function(box)
35937 if (!this.bodyEl) {
35938 return; // not rendered yet..
35942 if(!this.collapsed){
35943 this.el.dom.style.left = box.x + "px";
35944 this.el.dom.style.top = box.y + "px";
35945 this.updateBody(box.width, box.height);
35947 this.collapsedEl.dom.style.left = box.x + "px";
35948 this.collapsedEl.dom.style.top = box.y + "px";
35949 this.collapsedEl.setSize(box.width, box.height);
35952 this.tabs.autoSizeTabs();
35956 updateBody : function(w, h)
35959 this.el.setWidth(w);
35960 w -= this.el.getBorderWidth("rl");
35961 if(this.config.adjustments){
35962 w += this.config.adjustments[0];
35965 if(h !== null && h > 0){
35966 this.el.setHeight(h);
35967 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35968 h -= this.el.getBorderWidth("tb");
35969 if(this.config.adjustments){
35970 h += this.config.adjustments[1];
35972 this.bodyEl.setHeight(h);
35974 h = this.tabs.syncHeight(h);
35977 if(this.panelSize){
35978 w = w !== null ? w : this.panelSize.width;
35979 h = h !== null ? h : this.panelSize.height;
35981 if(this.activePanel){
35982 var el = this.activePanel.getEl();
35983 w = w !== null ? w : el.getWidth();
35984 h = h !== null ? h : el.getHeight();
35985 this.panelSize = {width: w, height: h};
35986 this.activePanel.setSize(w, h);
35988 if(Roo.isIE && this.tabs){
35989 this.tabs.el.repaint();
35994 * Returns the container element for this region.
35995 * @return {Roo.Element}
35997 getEl : function(){
36002 * Hides this region.
36005 //if(!this.collapsed){
36006 this.el.dom.style.left = "-2000px";
36009 // this.collapsedEl.dom.style.left = "-2000px";
36010 // this.collapsedEl.hide();
36012 this.visible = false;
36013 this.fireEvent("visibilitychange", this, false);
36017 * Shows this region if it was previously hidden.
36020 //if(!this.collapsed){
36023 // this.collapsedEl.show();
36025 this.visible = true;
36026 this.fireEvent("visibilitychange", this, true);
36029 closeClicked : function(){
36030 if(this.activePanel){
36031 this.remove(this.activePanel);
36035 collapseClick : function(e){
36037 e.stopPropagation();
36040 e.stopPropagation();
36046 * Collapses this region.
36047 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36050 collapse : function(skipAnim, skipCheck = false){
36051 if(this.collapsed) {
36055 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36057 this.collapsed = true;
36059 this.split.el.hide();
36061 if(this.config.animate && skipAnim !== true){
36062 this.fireEvent("invalidated", this);
36063 this.animateCollapse();
36065 this.el.setLocation(-20000,-20000);
36067 this.collapsedEl.show();
36068 this.fireEvent("collapsed", this);
36069 this.fireEvent("invalidated", this);
36075 animateCollapse : function(){
36080 * Expands this region if it was previously collapsed.
36081 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36082 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36085 expand : function(e, skipAnim){
36087 e.stopPropagation();
36089 if(!this.collapsed || this.el.hasActiveFx()) {
36093 this.afterSlideIn();
36096 this.collapsed = false;
36097 if(this.config.animate && skipAnim !== true){
36098 this.animateExpand();
36102 this.split.el.show();
36104 this.collapsedEl.setLocation(-2000,-2000);
36105 this.collapsedEl.hide();
36106 this.fireEvent("invalidated", this);
36107 this.fireEvent("expanded", this);
36111 animateExpand : function(){
36115 initTabs : function()
36117 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36119 var ts = new Roo.bootstrap.panel.Tabs({
36120 el: this.bodyEl.dom,
36121 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36122 disableTooltips: this.config.disableTabTips,
36123 toolbar : this.config.toolbar
36126 if(this.config.hideTabs){
36127 ts.stripWrap.setDisplayed(false);
36130 ts.resizeTabs = this.config.resizeTabs === true;
36131 ts.minTabWidth = this.config.minTabWidth || 40;
36132 ts.maxTabWidth = this.config.maxTabWidth || 250;
36133 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36134 ts.monitorResize = false;
36135 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36136 ts.bodyEl.addClass('roo-layout-tabs-body');
36137 this.panels.each(this.initPanelAsTab, this);
36140 initPanelAsTab : function(panel){
36141 var ti = this.tabs.addTab(
36145 this.config.closeOnTab && panel.isClosable(),
36148 if(panel.tabTip !== undefined){
36149 ti.setTooltip(panel.tabTip);
36151 ti.on("activate", function(){
36152 this.setActivePanel(panel);
36155 if(this.config.closeOnTab){
36156 ti.on("beforeclose", function(t, e){
36158 this.remove(panel);
36162 panel.tabItem = ti;
36167 updatePanelTitle : function(panel, title)
36169 if(this.activePanel == panel){
36170 this.updateTitle(title);
36173 var ti = this.tabs.getTab(panel.getEl().id);
36175 if(panel.tabTip !== undefined){
36176 ti.setTooltip(panel.tabTip);
36181 updateTitle : function(title){
36182 if(this.titleTextEl && !this.config.title){
36183 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36187 setActivePanel : function(panel)
36189 panel = this.getPanel(panel);
36190 if(this.activePanel && this.activePanel != panel){
36191 if(this.activePanel.setActiveState(false) === false){
36195 this.activePanel = panel;
36196 panel.setActiveState(true);
36197 if(this.panelSize){
36198 panel.setSize(this.panelSize.width, this.panelSize.height);
36201 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36203 this.updateTitle(panel.getTitle());
36205 this.fireEvent("invalidated", this);
36207 this.fireEvent("panelactivated", this, panel);
36211 * Shows the specified panel.
36212 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36213 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36215 showPanel : function(panel)
36217 panel = this.getPanel(panel);
36220 var tab = this.tabs.getTab(panel.getEl().id);
36221 if(tab.isHidden()){
36222 this.tabs.unhideTab(tab.id);
36226 this.setActivePanel(panel);
36233 * Get the active panel for this region.
36234 * @return {Roo.ContentPanel} The active panel or null
36236 getActivePanel : function(){
36237 return this.activePanel;
36240 validateVisibility : function(){
36241 if(this.panels.getCount() < 1){
36242 this.updateTitle(" ");
36243 this.closeBtn.hide();
36246 if(!this.isVisible()){
36253 * Adds the passed ContentPanel(s) to this region.
36254 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36255 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36257 add : function(panel)
36259 if(arguments.length > 1){
36260 for(var i = 0, len = arguments.length; i < len; i++) {
36261 this.add(arguments[i]);
36266 // if we have not been rendered yet, then we can not really do much of this..
36267 if (!this.bodyEl) {
36268 this.unrendered_panels.push(panel);
36275 if(this.hasPanel(panel)){
36276 this.showPanel(panel);
36279 panel.setRegion(this);
36280 this.panels.add(panel);
36281 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36282 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36283 // and hide them... ???
36284 this.bodyEl.dom.appendChild(panel.getEl().dom);
36285 if(panel.background !== true){
36286 this.setActivePanel(panel);
36288 this.fireEvent("paneladded", this, panel);
36295 this.initPanelAsTab(panel);
36299 if(panel.background !== true){
36300 this.tabs.activate(panel.getEl().id);
36302 this.fireEvent("paneladded", this, panel);
36307 * Hides the tab for the specified panel.
36308 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36310 hidePanel : function(panel){
36311 if(this.tabs && (panel = this.getPanel(panel))){
36312 this.tabs.hideTab(panel.getEl().id);
36317 * Unhides the tab for a previously hidden panel.
36318 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36320 unhidePanel : function(panel){
36321 if(this.tabs && (panel = this.getPanel(panel))){
36322 this.tabs.unhideTab(panel.getEl().id);
36326 clearPanels : function(){
36327 while(this.panels.getCount() > 0){
36328 this.remove(this.panels.first());
36333 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36334 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36335 * @param {Boolean} preservePanel Overrides the config preservePanel option
36336 * @return {Roo.ContentPanel} The panel that was removed
36338 remove : function(panel, preservePanel)
36340 panel = this.getPanel(panel);
36345 this.fireEvent("beforeremove", this, panel, e);
36346 if(e.cancel === true){
36349 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36350 var panelId = panel.getId();
36351 this.panels.removeKey(panelId);
36353 document.body.appendChild(panel.getEl().dom);
36356 this.tabs.removeTab(panel.getEl().id);
36357 }else if (!preservePanel){
36358 this.bodyEl.dom.removeChild(panel.getEl().dom);
36360 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36361 var p = this.panels.first();
36362 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36363 tempEl.appendChild(p.getEl().dom);
36364 this.bodyEl.update("");
36365 this.bodyEl.dom.appendChild(p.getEl().dom);
36367 this.updateTitle(p.getTitle());
36369 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36370 this.setActivePanel(p);
36372 panel.setRegion(null);
36373 if(this.activePanel == panel){
36374 this.activePanel = null;
36376 if(this.config.autoDestroy !== false && preservePanel !== true){
36377 try{panel.destroy();}catch(e){}
36379 this.fireEvent("panelremoved", this, panel);
36384 * Returns the TabPanel component used by this region
36385 * @return {Roo.TabPanel}
36387 getTabs : function(){
36391 createTool : function(parentEl, className){
36392 var btn = Roo.DomHelper.append(parentEl, {
36394 cls: "x-layout-tools-button",
36397 cls: "roo-layout-tools-button-inner " + className,
36401 btn.addClassOnOver("roo-layout-tools-button-over");
36406 * Ext JS Library 1.1.1
36407 * Copyright(c) 2006-2007, Ext JS, LLC.
36409 * Originally Released Under LGPL - original licence link has changed is not relivant.
36412 * <script type="text/javascript">
36418 * @class Roo.SplitLayoutRegion
36419 * @extends Roo.LayoutRegion
36420 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36422 Roo.bootstrap.layout.Split = function(config){
36423 this.cursor = config.cursor;
36424 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36427 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36429 splitTip : "Drag to resize.",
36430 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36431 useSplitTips : false,
36433 applyConfig : function(config){
36434 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36437 onRender : function(ctr,pos) {
36439 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36440 if(!this.config.split){
36445 var splitEl = Roo.DomHelper.append(ctr.dom, {
36447 id: this.el.id + "-split",
36448 cls: "roo-layout-split roo-layout-split-"+this.position,
36451 /** The SplitBar for this region
36452 * @type Roo.SplitBar */
36453 // does not exist yet...
36454 Roo.log([this.position, this.orientation]);
36456 this.split = new Roo.bootstrap.SplitBar({
36457 dragElement : splitEl,
36458 resizingElement: this.el,
36459 orientation : this.orientation
36462 this.split.on("moved", this.onSplitMove, this);
36463 this.split.useShim = this.config.useShim === true;
36464 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36465 if(this.useSplitTips){
36466 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36468 //if(config.collapsible){
36469 // this.split.el.on("dblclick", this.collapse, this);
36472 if(typeof this.config.minSize != "undefined"){
36473 this.split.minSize = this.config.minSize;
36475 if(typeof this.config.maxSize != "undefined"){
36476 this.split.maxSize = this.config.maxSize;
36478 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36479 this.hideSplitter();
36484 getHMaxSize : function(){
36485 var cmax = this.config.maxSize || 10000;
36486 var center = this.mgr.getRegion("center");
36487 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36490 getVMaxSize : function(){
36491 var cmax = this.config.maxSize || 10000;
36492 var center = this.mgr.getRegion("center");
36493 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36496 onSplitMove : function(split, newSize){
36497 this.fireEvent("resized", this, newSize);
36501 * Returns the {@link Roo.SplitBar} for this region.
36502 * @return {Roo.SplitBar}
36504 getSplitBar : function(){
36509 this.hideSplitter();
36510 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36513 hideSplitter : function(){
36515 this.split.el.setLocation(-2000,-2000);
36516 this.split.el.hide();
36522 this.split.el.show();
36524 Roo.bootstrap.layout.Split.superclass.show.call(this);
36527 beforeSlide: function(){
36528 if(Roo.isGecko){// firefox overflow auto bug workaround
36529 this.bodyEl.clip();
36531 this.tabs.bodyEl.clip();
36533 if(this.activePanel){
36534 this.activePanel.getEl().clip();
36536 if(this.activePanel.beforeSlide){
36537 this.activePanel.beforeSlide();
36543 afterSlide : function(){
36544 if(Roo.isGecko){// firefox overflow auto bug workaround
36545 this.bodyEl.unclip();
36547 this.tabs.bodyEl.unclip();
36549 if(this.activePanel){
36550 this.activePanel.getEl().unclip();
36551 if(this.activePanel.afterSlide){
36552 this.activePanel.afterSlide();
36558 initAutoHide : function(){
36559 if(this.autoHide !== false){
36560 if(!this.autoHideHd){
36561 var st = new Roo.util.DelayedTask(this.slideIn, this);
36562 this.autoHideHd = {
36563 "mouseout": function(e){
36564 if(!e.within(this.el, true)){
36568 "mouseover" : function(e){
36574 this.el.on(this.autoHideHd);
36578 clearAutoHide : function(){
36579 if(this.autoHide !== false){
36580 this.el.un("mouseout", this.autoHideHd.mouseout);
36581 this.el.un("mouseover", this.autoHideHd.mouseover);
36585 clearMonitor : function(){
36586 Roo.get(document).un("click", this.slideInIf, this);
36589 // these names are backwards but not changed for compat
36590 slideOut : function(){
36591 if(this.isSlid || this.el.hasActiveFx()){
36594 this.isSlid = true;
36595 if(this.collapseBtn){
36596 this.collapseBtn.hide();
36598 this.closeBtnState = this.closeBtn.getStyle('display');
36599 this.closeBtn.hide();
36601 this.stickBtn.show();
36604 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36605 this.beforeSlide();
36606 this.el.setStyle("z-index", 10001);
36607 this.el.slideIn(this.getSlideAnchor(), {
36608 callback: function(){
36610 this.initAutoHide();
36611 Roo.get(document).on("click", this.slideInIf, this);
36612 this.fireEvent("slideshow", this);
36619 afterSlideIn : function(){
36620 this.clearAutoHide();
36621 this.isSlid = false;
36622 this.clearMonitor();
36623 this.el.setStyle("z-index", "");
36624 if(this.collapseBtn){
36625 this.collapseBtn.show();
36627 this.closeBtn.setStyle('display', this.closeBtnState);
36629 this.stickBtn.hide();
36631 this.fireEvent("slidehide", this);
36634 slideIn : function(cb){
36635 if(!this.isSlid || this.el.hasActiveFx()){
36639 this.isSlid = false;
36640 this.beforeSlide();
36641 this.el.slideOut(this.getSlideAnchor(), {
36642 callback: function(){
36643 this.el.setLeftTop(-10000, -10000);
36645 this.afterSlideIn();
36653 slideInIf : function(e){
36654 if(!e.within(this.el)){
36659 animateCollapse : function(){
36660 this.beforeSlide();
36661 this.el.setStyle("z-index", 20000);
36662 var anchor = this.getSlideAnchor();
36663 this.el.slideOut(anchor, {
36664 callback : function(){
36665 this.el.setStyle("z-index", "");
36666 this.collapsedEl.slideIn(anchor, {duration:.3});
36668 this.el.setLocation(-10000,-10000);
36670 this.fireEvent("collapsed", this);
36677 animateExpand : function(){
36678 this.beforeSlide();
36679 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36680 this.el.setStyle("z-index", 20000);
36681 this.collapsedEl.hide({
36684 this.el.slideIn(this.getSlideAnchor(), {
36685 callback : function(){
36686 this.el.setStyle("z-index", "");
36689 this.split.el.show();
36691 this.fireEvent("invalidated", this);
36692 this.fireEvent("expanded", this);
36720 getAnchor : function(){
36721 return this.anchors[this.position];
36724 getCollapseAnchor : function(){
36725 return this.canchors[this.position];
36728 getSlideAnchor : function(){
36729 return this.sanchors[this.position];
36732 getAlignAdj : function(){
36733 var cm = this.cmargins;
36734 switch(this.position){
36750 getExpandAdj : function(){
36751 var c = this.collapsedEl, cm = this.cmargins;
36752 switch(this.position){
36754 return [-(cm.right+c.getWidth()+cm.left), 0];
36757 return [cm.right+c.getWidth()+cm.left, 0];
36760 return [0, -(cm.top+cm.bottom+c.getHeight())];
36763 return [0, cm.top+cm.bottom+c.getHeight()];
36769 * Ext JS Library 1.1.1
36770 * Copyright(c) 2006-2007, Ext JS, LLC.
36772 * Originally Released Under LGPL - original licence link has changed is not relivant.
36775 * <script type="text/javascript">
36778 * These classes are private internal classes
36780 Roo.bootstrap.layout.Center = function(config){
36781 config.region = "center";
36782 Roo.bootstrap.layout.Region.call(this, config);
36783 this.visible = true;
36784 this.minWidth = config.minWidth || 20;
36785 this.minHeight = config.minHeight || 20;
36788 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36790 // center panel can't be hidden
36794 // center panel can't be hidden
36797 getMinWidth: function(){
36798 return this.minWidth;
36801 getMinHeight: function(){
36802 return this.minHeight;
36815 Roo.bootstrap.layout.North = function(config)
36817 config.region = 'north';
36818 config.cursor = 'n-resize';
36820 Roo.bootstrap.layout.Split.call(this, config);
36824 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36825 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36826 this.split.el.addClass("roo-layout-split-v");
36828 var size = config.initialSize || config.height;
36829 if(typeof size != "undefined"){
36830 this.el.setHeight(size);
36833 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36835 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36839 getBox : function(){
36840 if(this.collapsed){
36841 return this.collapsedEl.getBox();
36843 var box = this.el.getBox();
36845 box.height += this.split.el.getHeight();
36850 updateBox : function(box){
36851 if(this.split && !this.collapsed){
36852 box.height -= this.split.el.getHeight();
36853 this.split.el.setLeft(box.x);
36854 this.split.el.setTop(box.y+box.height);
36855 this.split.el.setWidth(box.width);
36857 if(this.collapsed){
36858 this.updateBody(box.width, null);
36860 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36868 Roo.bootstrap.layout.South = function(config){
36869 config.region = 'south';
36870 config.cursor = 's-resize';
36871 Roo.bootstrap.layout.Split.call(this, config);
36873 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36874 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36875 this.split.el.addClass("roo-layout-split-v");
36877 var size = config.initialSize || config.height;
36878 if(typeof size != "undefined"){
36879 this.el.setHeight(size);
36883 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36884 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36885 getBox : function(){
36886 if(this.collapsed){
36887 return this.collapsedEl.getBox();
36889 var box = this.el.getBox();
36891 var sh = this.split.el.getHeight();
36898 updateBox : function(box){
36899 if(this.split && !this.collapsed){
36900 var sh = this.split.el.getHeight();
36903 this.split.el.setLeft(box.x);
36904 this.split.el.setTop(box.y-sh);
36905 this.split.el.setWidth(box.width);
36907 if(this.collapsed){
36908 this.updateBody(box.width, null);
36910 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36914 Roo.bootstrap.layout.East = function(config){
36915 config.region = "east";
36916 config.cursor = "e-resize";
36917 Roo.bootstrap.layout.Split.call(this, config);
36919 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36920 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36921 this.split.el.addClass("roo-layout-split-h");
36923 var size = config.initialSize || config.width;
36924 if(typeof size != "undefined"){
36925 this.el.setWidth(size);
36928 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36929 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36930 getBox : function(){
36931 if(this.collapsed){
36932 return this.collapsedEl.getBox();
36934 var box = this.el.getBox();
36936 var sw = this.split.el.getWidth();
36943 updateBox : function(box){
36944 if(this.split && !this.collapsed){
36945 var sw = this.split.el.getWidth();
36947 this.split.el.setLeft(box.x);
36948 this.split.el.setTop(box.y);
36949 this.split.el.setHeight(box.height);
36952 if(this.collapsed){
36953 this.updateBody(null, box.height);
36955 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36959 Roo.bootstrap.layout.West = function(config){
36960 config.region = "west";
36961 config.cursor = "w-resize";
36963 Roo.bootstrap.layout.Split.call(this, config);
36965 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36966 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36967 this.split.el.addClass("roo-layout-split-h");
36971 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36972 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36974 onRender: function(ctr, pos)
36976 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36977 var size = this.config.initialSize || this.config.width;
36978 if(typeof size != "undefined"){
36979 this.el.setWidth(size);
36983 getBox : function(){
36984 if(this.collapsed){
36985 return this.collapsedEl.getBox();
36987 var box = this.el.getBox();
36989 box.width += this.split.el.getWidth();
36994 updateBox : function(box){
36995 if(this.split && !this.collapsed){
36996 var sw = this.split.el.getWidth();
36998 this.split.el.setLeft(box.x+box.width);
36999 this.split.el.setTop(box.y);
37000 this.split.el.setHeight(box.height);
37002 if(this.collapsed){
37003 this.updateBody(null, box.height);
37005 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37008 Roo.namespace("Roo.bootstrap.panel");/*
37010 * Ext JS Library 1.1.1
37011 * Copyright(c) 2006-2007, Ext JS, LLC.
37013 * Originally Released Under LGPL - original licence link has changed is not relivant.
37016 * <script type="text/javascript">
37019 * @class Roo.ContentPanel
37020 * @extends Roo.util.Observable
37021 * A basic ContentPanel element.
37022 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37023 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37024 * @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
37025 * @cfg {Boolean} closable True if the panel can be closed/removed
37026 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37027 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37028 * @cfg {Toolbar} toolbar A toolbar for this panel
37029 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37030 * @cfg {String} title The title for this panel
37031 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37032 * @cfg {String} url Calls {@link #setUrl} with this value
37033 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37034 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37035 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37036 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37037 * @cfg {Boolean} badges render the badges
37040 * Create a new ContentPanel.
37041 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37042 * @param {String/Object} config A string to set only the title or a config object
37043 * @param {String} content (optional) Set the HTML content for this panel
37044 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37046 Roo.bootstrap.panel.Content = function( config){
37048 this.tpl = config.tpl || false;
37050 var el = config.el;
37051 var content = config.content;
37053 if(config.autoCreate){ // xtype is available if this is called from factory
37056 this.el = Roo.get(el);
37057 if(!this.el && config && config.autoCreate){
37058 if(typeof config.autoCreate == "object"){
37059 if(!config.autoCreate.id){
37060 config.autoCreate.id = config.id||el;
37062 this.el = Roo.DomHelper.append(document.body,
37063 config.autoCreate, true);
37065 var elcfg = { tag: "div",
37066 cls: "roo-layout-inactive-content",
37070 elcfg.html = config.html;
37074 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37077 this.closable = false;
37078 this.loaded = false;
37079 this.active = false;
37082 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37084 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37086 this.wrapEl = this.el; //this.el.wrap();
37088 if (config.toolbar.items) {
37089 ti = config.toolbar.items ;
37090 delete config.toolbar.items ;
37094 this.toolbar.render(this.wrapEl, 'before');
37095 for(var i =0;i < ti.length;i++) {
37096 // Roo.log(['add child', items[i]]);
37097 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37099 this.toolbar.items = nitems;
37100 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37101 delete config.toolbar;
37105 // xtype created footer. - not sure if will work as we normally have to render first..
37106 if (this.footer && !this.footer.el && this.footer.xtype) {
37107 if (!this.wrapEl) {
37108 this.wrapEl = this.el.wrap();
37111 this.footer.container = this.wrapEl.createChild();
37113 this.footer = Roo.factory(this.footer, Roo);
37118 if(typeof config == "string"){
37119 this.title = config;
37121 Roo.apply(this, config);
37125 this.resizeEl = Roo.get(this.resizeEl, true);
37127 this.resizeEl = this.el;
37129 // handle view.xtype
37137 * Fires when this panel is activated.
37138 * @param {Roo.ContentPanel} this
37142 * @event deactivate
37143 * Fires when this panel is activated.
37144 * @param {Roo.ContentPanel} this
37146 "deactivate" : true,
37150 * Fires when this panel is resized if fitToFrame is true.
37151 * @param {Roo.ContentPanel} this
37152 * @param {Number} width The width after any component adjustments
37153 * @param {Number} height The height after any component adjustments
37159 * Fires when this tab is created
37160 * @param {Roo.ContentPanel} this
37171 if(this.autoScroll){
37172 this.resizeEl.setStyle("overflow", "auto");
37174 // fix randome scrolling
37175 //this.el.on('scroll', function() {
37176 // Roo.log('fix random scolling');
37177 // this.scrollTo('top',0);
37180 content = content || this.content;
37182 this.setContent(content);
37184 if(config && config.url){
37185 this.setUrl(this.url, this.params, this.loadOnce);
37190 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37192 if (this.view && typeof(this.view.xtype) != 'undefined') {
37193 this.view.el = this.el.appendChild(document.createElement("div"));
37194 this.view = Roo.factory(this.view);
37195 this.view.render && this.view.render(false, '');
37199 this.fireEvent('render', this);
37202 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37206 setRegion : function(region){
37207 this.region = region;
37208 this.setActiveClass(region && !this.background);
37212 setActiveClass: function(state)
37215 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37216 this.el.setStyle('position','relative');
37218 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37219 this.el.setStyle('position', 'absolute');
37224 * Returns the toolbar for this Panel if one was configured.
37225 * @return {Roo.Toolbar}
37227 getToolbar : function(){
37228 return this.toolbar;
37231 setActiveState : function(active)
37233 this.active = active;
37234 this.setActiveClass(active);
37236 if(this.fireEvent("deactivate", this) === false){
37241 this.fireEvent("activate", this);
37245 * Updates this panel's element
37246 * @param {String} content The new content
37247 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37249 setContent : function(content, loadScripts){
37250 this.el.update(content, loadScripts);
37253 ignoreResize : function(w, h){
37254 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37257 this.lastSize = {width: w, height: h};
37262 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37263 * @return {Roo.UpdateManager} The UpdateManager
37265 getUpdateManager : function(){
37266 return this.el.getUpdateManager();
37269 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37270 * @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:
37273 url: "your-url.php",
37274 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37275 callback: yourFunction,
37276 scope: yourObject, //(optional scope)
37279 text: "Loading...",
37284 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37285 * 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.
37286 * @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}
37287 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37288 * @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.
37289 * @return {Roo.ContentPanel} this
37292 var um = this.el.getUpdateManager();
37293 um.update.apply(um, arguments);
37299 * 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.
37300 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37301 * @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)
37302 * @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)
37303 * @return {Roo.UpdateManager} The UpdateManager
37305 setUrl : function(url, params, loadOnce){
37306 if(this.refreshDelegate){
37307 this.removeListener("activate", this.refreshDelegate);
37309 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37310 this.on("activate", this.refreshDelegate);
37311 return this.el.getUpdateManager();
37314 _handleRefresh : function(url, params, loadOnce){
37315 if(!loadOnce || !this.loaded){
37316 var updater = this.el.getUpdateManager();
37317 updater.update(url, params, this._setLoaded.createDelegate(this));
37321 _setLoaded : function(){
37322 this.loaded = true;
37326 * Returns this panel's id
37329 getId : function(){
37334 * Returns this panel's element - used by regiosn to add.
37335 * @return {Roo.Element}
37337 getEl : function(){
37338 return this.wrapEl || this.el;
37343 adjustForComponents : function(width, height)
37345 //Roo.log('adjustForComponents ');
37346 if(this.resizeEl != this.el){
37347 width -= this.el.getFrameWidth('lr');
37348 height -= this.el.getFrameWidth('tb');
37351 var te = this.toolbar.getEl();
37352 te.setWidth(width);
37353 height -= te.getHeight();
37356 var te = this.footer.getEl();
37357 te.setWidth(width);
37358 height -= te.getHeight();
37362 if(this.adjustments){
37363 width += this.adjustments[0];
37364 height += this.adjustments[1];
37366 return {"width": width, "height": height};
37369 setSize : function(width, height){
37370 if(this.fitToFrame && !this.ignoreResize(width, height)){
37371 if(this.fitContainer && this.resizeEl != this.el){
37372 this.el.setSize(width, height);
37374 var size = this.adjustForComponents(width, height);
37375 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37376 this.fireEvent('resize', this, size.width, size.height);
37381 * Returns this panel's title
37384 getTitle : function(){
37386 if (typeof(this.title) != 'object') {
37391 for (var k in this.title) {
37392 if (!this.title.hasOwnProperty(k)) {
37396 if (k.indexOf('-') >= 0) {
37397 var s = k.split('-');
37398 for (var i = 0; i<s.length; i++) {
37399 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37402 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37409 * Set this panel's title
37410 * @param {String} title
37412 setTitle : function(title){
37413 this.title = title;
37415 this.region.updatePanelTitle(this, title);
37420 * Returns true is this panel was configured to be closable
37421 * @return {Boolean}
37423 isClosable : function(){
37424 return this.closable;
37427 beforeSlide : function(){
37429 this.resizeEl.clip();
37432 afterSlide : function(){
37434 this.resizeEl.unclip();
37438 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37439 * Will fail silently if the {@link #setUrl} method has not been called.
37440 * This does not activate the panel, just updates its content.
37442 refresh : function(){
37443 if(this.refreshDelegate){
37444 this.loaded = false;
37445 this.refreshDelegate();
37450 * Destroys this panel
37452 destroy : function(){
37453 this.el.removeAllListeners();
37454 var tempEl = document.createElement("span");
37455 tempEl.appendChild(this.el.dom);
37456 tempEl.innerHTML = "";
37462 * form - if the content panel contains a form - this is a reference to it.
37463 * @type {Roo.form.Form}
37467 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37468 * This contains a reference to it.
37474 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37484 * @param {Object} cfg Xtype definition of item to add.
37488 getChildContainer: function () {
37489 return this.getEl();
37494 var ret = new Roo.factory(cfg);
37499 if (cfg.xtype.match(/^Form$/)) {
37502 //if (this.footer) {
37503 // el = this.footer.container.insertSibling(false, 'before');
37505 el = this.el.createChild();
37508 this.form = new Roo.form.Form(cfg);
37511 if ( this.form.allItems.length) {
37512 this.form.render(el.dom);
37516 // should only have one of theses..
37517 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37518 // views.. should not be just added - used named prop 'view''
37520 cfg.el = this.el.appendChild(document.createElement("div"));
37523 var ret = new Roo.factory(cfg);
37525 ret.render && ret.render(false, ''); // render blank..
37535 * @class Roo.bootstrap.panel.Grid
37536 * @extends Roo.bootstrap.panel.Content
37538 * Create a new GridPanel.
37539 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37540 * @param {Object} config A the config object
37546 Roo.bootstrap.panel.Grid = function(config)
37550 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37551 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37553 config.el = this.wrapper;
37554 //this.el = this.wrapper;
37556 if (config.container) {
37557 // ctor'ed from a Border/panel.grid
37560 this.wrapper.setStyle("overflow", "hidden");
37561 this.wrapper.addClass('roo-grid-container');
37566 if(config.toolbar){
37567 var tool_el = this.wrapper.createChild();
37568 this.toolbar = Roo.factory(config.toolbar);
37570 if (config.toolbar.items) {
37571 ti = config.toolbar.items ;
37572 delete config.toolbar.items ;
37576 this.toolbar.render(tool_el);
37577 for(var i =0;i < ti.length;i++) {
37578 // Roo.log(['add child', items[i]]);
37579 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37581 this.toolbar.items = nitems;
37583 delete config.toolbar;
37586 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37587 config.grid.scrollBody = true;;
37588 config.grid.monitorWindowResize = false; // turn off autosizing
37589 config.grid.autoHeight = false;
37590 config.grid.autoWidth = false;
37592 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37594 if (config.background) {
37595 // render grid on panel activation (if panel background)
37596 this.on('activate', function(gp) {
37597 if (!gp.grid.rendered) {
37598 gp.grid.render(this.wrapper);
37599 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37604 this.grid.render(this.wrapper);
37605 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37608 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37609 // ??? needed ??? config.el = this.wrapper;
37614 // xtype created footer. - not sure if will work as we normally have to render first..
37615 if (this.footer && !this.footer.el && this.footer.xtype) {
37617 var ctr = this.grid.getView().getFooterPanel(true);
37618 this.footer.dataSource = this.grid.dataSource;
37619 this.footer = Roo.factory(this.footer, Roo);
37620 this.footer.render(ctr);
37630 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37631 getId : function(){
37632 return this.grid.id;
37636 * Returns the grid for this panel
37637 * @return {Roo.bootstrap.Table}
37639 getGrid : function(){
37643 setSize : function(width, height){
37644 if(!this.ignoreResize(width, height)){
37645 var grid = this.grid;
37646 var size = this.adjustForComponents(width, height);
37647 var gridel = grid.getGridEl();
37648 gridel.setSize(size.width, size.height);
37650 var thd = grid.getGridEl().select('thead',true).first();
37651 var tbd = grid.getGridEl().select('tbody', true).first();
37653 tbd.setSize(width, height - thd.getHeight());
37662 beforeSlide : function(){
37663 this.grid.getView().scroller.clip();
37666 afterSlide : function(){
37667 this.grid.getView().scroller.unclip();
37670 destroy : function(){
37671 this.grid.destroy();
37673 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37678 * @class Roo.bootstrap.panel.Nest
37679 * @extends Roo.bootstrap.panel.Content
37681 * Create a new Panel, that can contain a layout.Border.
37684 * @param {Roo.BorderLayout} layout The layout for this panel
37685 * @param {String/Object} config A string to set only the title or a config object
37687 Roo.bootstrap.panel.Nest = function(config)
37689 // construct with only one argument..
37690 /* FIXME - implement nicer consturctors
37691 if (layout.layout) {
37693 layout = config.layout;
37694 delete config.layout;
37696 if (layout.xtype && !layout.getEl) {
37697 // then layout needs constructing..
37698 layout = Roo.factory(layout, Roo);
37702 config.el = config.layout.getEl();
37704 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37706 config.layout.monitorWindowResize = false; // turn off autosizing
37707 this.layout = config.layout;
37708 this.layout.getEl().addClass("roo-layout-nested-layout");
37715 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37717 setSize : function(width, height){
37718 if(!this.ignoreResize(width, height)){
37719 var size = this.adjustForComponents(width, height);
37720 var el = this.layout.getEl();
37721 if (size.height < 1) {
37722 el.setWidth(size.width);
37724 el.setSize(size.width, size.height);
37726 var touch = el.dom.offsetWidth;
37727 this.layout.layout();
37728 // ie requires a double layout on the first pass
37729 if(Roo.isIE && !this.initialized){
37730 this.initialized = true;
37731 this.layout.layout();
37736 // activate all subpanels if not currently active..
37738 setActiveState : function(active){
37739 this.active = active;
37740 this.setActiveClass(active);
37743 this.fireEvent("deactivate", this);
37747 this.fireEvent("activate", this);
37748 // not sure if this should happen before or after..
37749 if (!this.layout) {
37750 return; // should not happen..
37753 for (var r in this.layout.regions) {
37754 reg = this.layout.getRegion(r);
37755 if (reg.getActivePanel()) {
37756 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37757 reg.setActivePanel(reg.getActivePanel());
37760 if (!reg.panels.length) {
37763 reg.showPanel(reg.getPanel(0));
37772 * Returns the nested BorderLayout for this panel
37773 * @return {Roo.BorderLayout}
37775 getLayout : function(){
37776 return this.layout;
37780 * Adds a xtype elements to the layout of the nested panel
37784 xtype : 'ContentPanel',
37791 xtype : 'NestedLayoutPanel',
37797 items : [ ... list of content panels or nested layout panels.. ]
37801 * @param {Object} cfg Xtype definition of item to add.
37803 addxtype : function(cfg) {
37804 return this.layout.addxtype(cfg);
37809 * Ext JS Library 1.1.1
37810 * Copyright(c) 2006-2007, Ext JS, LLC.
37812 * Originally Released Under LGPL - original licence link has changed is not relivant.
37815 * <script type="text/javascript">
37818 * @class Roo.TabPanel
37819 * @extends Roo.util.Observable
37820 * A lightweight tab container.
37824 // basic tabs 1, built from existing content
37825 var tabs = new Roo.TabPanel("tabs1");
37826 tabs.addTab("script", "View Script");
37827 tabs.addTab("markup", "View Markup");
37828 tabs.activate("script");
37830 // more advanced tabs, built from javascript
37831 var jtabs = new Roo.TabPanel("jtabs");
37832 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37834 // set up the UpdateManager
37835 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37836 var updater = tab2.getUpdateManager();
37837 updater.setDefaultUrl("ajax1.htm");
37838 tab2.on('activate', updater.refresh, updater, true);
37840 // Use setUrl for Ajax loading
37841 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37842 tab3.setUrl("ajax2.htm", null, true);
37845 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37848 jtabs.activate("jtabs-1");
37851 * Create a new TabPanel.
37852 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37853 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37855 Roo.bootstrap.panel.Tabs = function(config){
37857 * The container element for this TabPanel.
37858 * @type Roo.Element
37860 this.el = Roo.get(config.el);
37863 if(typeof config == "boolean"){
37864 this.tabPosition = config ? "bottom" : "top";
37866 Roo.apply(this, config);
37870 if(this.tabPosition == "bottom"){
37871 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37872 this.el.addClass("roo-tabs-bottom");
37874 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37875 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37876 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37878 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37880 if(this.tabPosition != "bottom"){
37881 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37882 * @type Roo.Element
37884 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37885 this.el.addClass("roo-tabs-top");
37889 this.bodyEl.setStyle("position", "relative");
37891 this.active = null;
37892 this.activateDelegate = this.activate.createDelegate(this);
37897 * Fires when the active tab changes
37898 * @param {Roo.TabPanel} this
37899 * @param {Roo.TabPanelItem} activePanel The new active tab
37903 * @event beforetabchange
37904 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37905 * @param {Roo.TabPanel} this
37906 * @param {Object} e Set cancel to true on this object to cancel the tab change
37907 * @param {Roo.TabPanelItem} tab The tab being changed to
37909 "beforetabchange" : true
37912 Roo.EventManager.onWindowResize(this.onResize, this);
37913 this.cpad = this.el.getPadding("lr");
37914 this.hiddenCount = 0;
37917 // toolbar on the tabbar support...
37918 if (this.toolbar) {
37919 alert("no toolbar support yet");
37920 this.toolbar = false;
37922 var tcfg = this.toolbar;
37923 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37924 this.toolbar = new Roo.Toolbar(tcfg);
37925 if (Roo.isSafari) {
37926 var tbl = tcfg.container.child('table', true);
37927 tbl.setAttribute('width', '100%');
37935 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37938 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37940 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37942 tabPosition : "top",
37944 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37946 currentTabWidth : 0,
37948 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37952 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37956 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37958 preferredTabWidth : 175,
37960 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37962 resizeTabs : false,
37964 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37966 monitorResize : true,
37968 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37973 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37974 * @param {String} id The id of the div to use <b>or create</b>
37975 * @param {String} text The text for the tab
37976 * @param {String} content (optional) Content to put in the TabPanelItem body
37977 * @param {Boolean} closable (optional) True to create a close icon on the tab
37978 * @return {Roo.TabPanelItem} The created TabPanelItem
37980 addTab : function(id, text, content, closable, tpl)
37982 var item = new Roo.bootstrap.panel.TabItem({
37986 closable : closable,
37989 this.addTabItem(item);
37991 item.setContent(content);
37997 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37998 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37999 * @return {Roo.TabPanelItem}
38001 getTab : function(id){
38002 return this.items[id];
38006 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38007 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38009 hideTab : function(id){
38010 var t = this.items[id];
38013 this.hiddenCount++;
38014 this.autoSizeTabs();
38019 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38020 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38022 unhideTab : function(id){
38023 var t = this.items[id];
38025 t.setHidden(false);
38026 this.hiddenCount--;
38027 this.autoSizeTabs();
38032 * Adds an existing {@link Roo.TabPanelItem}.
38033 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38035 addTabItem : function(item){
38036 this.items[item.id] = item;
38037 this.items.push(item);
38038 // if(this.resizeTabs){
38039 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38040 // this.autoSizeTabs();
38042 // item.autoSize();
38047 * Removes a {@link Roo.TabPanelItem}.
38048 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38050 removeTab : function(id){
38051 var items = this.items;
38052 var tab = items[id];
38053 if(!tab) { return; }
38054 var index = items.indexOf(tab);
38055 if(this.active == tab && items.length > 1){
38056 var newTab = this.getNextAvailable(index);
38061 this.stripEl.dom.removeChild(tab.pnode.dom);
38062 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38063 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38065 items.splice(index, 1);
38066 delete this.items[tab.id];
38067 tab.fireEvent("close", tab);
38068 tab.purgeListeners();
38069 this.autoSizeTabs();
38072 getNextAvailable : function(start){
38073 var items = this.items;
38075 // look for a next tab that will slide over to
38076 // replace the one being removed
38077 while(index < items.length){
38078 var item = items[++index];
38079 if(item && !item.isHidden()){
38083 // if one isn't found select the previous tab (on the left)
38086 var item = items[--index];
38087 if(item && !item.isHidden()){
38095 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38096 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38098 disableTab : function(id){
38099 var tab = this.items[id];
38100 if(tab && this.active != tab){
38106 * Enables a {@link Roo.TabPanelItem} that is disabled.
38107 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38109 enableTab : function(id){
38110 var tab = this.items[id];
38115 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38116 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38117 * @return {Roo.TabPanelItem} The TabPanelItem.
38119 activate : function(id){
38120 var tab = this.items[id];
38124 if(tab == this.active || tab.disabled){
38128 this.fireEvent("beforetabchange", this, e, tab);
38129 if(e.cancel !== true && !tab.disabled){
38131 this.active.hide();
38133 this.active = this.items[id];
38134 this.active.show();
38135 this.fireEvent("tabchange", this, this.active);
38141 * Gets the active {@link Roo.TabPanelItem}.
38142 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38144 getActiveTab : function(){
38145 return this.active;
38149 * Updates the tab body element to fit the height of the container element
38150 * for overflow scrolling
38151 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38153 syncHeight : function(targetHeight){
38154 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38155 var bm = this.bodyEl.getMargins();
38156 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38157 this.bodyEl.setHeight(newHeight);
38161 onResize : function(){
38162 if(this.monitorResize){
38163 this.autoSizeTabs();
38168 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38170 beginUpdate : function(){
38171 this.updating = true;
38175 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38177 endUpdate : function(){
38178 this.updating = false;
38179 this.autoSizeTabs();
38183 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38185 autoSizeTabs : function(){
38186 var count = this.items.length;
38187 var vcount = count - this.hiddenCount;
38188 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38191 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38192 var availWidth = Math.floor(w / vcount);
38193 var b = this.stripBody;
38194 if(b.getWidth() > w){
38195 var tabs = this.items;
38196 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38197 if(availWidth < this.minTabWidth){
38198 /*if(!this.sleft){ // incomplete scrolling code
38199 this.createScrollButtons();
38202 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38205 if(this.currentTabWidth < this.preferredTabWidth){
38206 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38212 * Returns the number of tabs in this TabPanel.
38215 getCount : function(){
38216 return this.items.length;
38220 * Resizes all the tabs to the passed width
38221 * @param {Number} The new width
38223 setTabWidth : function(width){
38224 this.currentTabWidth = width;
38225 for(var i = 0, len = this.items.length; i < len; i++) {
38226 if(!this.items[i].isHidden()) {
38227 this.items[i].setWidth(width);
38233 * Destroys this TabPanel
38234 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38236 destroy : function(removeEl){
38237 Roo.EventManager.removeResizeListener(this.onResize, this);
38238 for(var i = 0, len = this.items.length; i < len; i++){
38239 this.items[i].purgeListeners();
38241 if(removeEl === true){
38242 this.el.update("");
38247 createStrip : function(container)
38249 var strip = document.createElement("nav");
38250 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38251 container.appendChild(strip);
38255 createStripList : function(strip)
38257 // div wrapper for retard IE
38258 // returns the "tr" element.
38259 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38260 //'<div class="x-tabs-strip-wrap">'+
38261 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38262 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38263 return strip.firstChild; //.firstChild.firstChild.firstChild;
38265 createBody : function(container)
38267 var body = document.createElement("div");
38268 Roo.id(body, "tab-body");
38269 //Roo.fly(body).addClass("x-tabs-body");
38270 Roo.fly(body).addClass("tab-content");
38271 container.appendChild(body);
38274 createItemBody :function(bodyEl, id){
38275 var body = Roo.getDom(id);
38277 body = document.createElement("div");
38280 //Roo.fly(body).addClass("x-tabs-item-body");
38281 Roo.fly(body).addClass("tab-pane");
38282 bodyEl.insertBefore(body, bodyEl.firstChild);
38286 createStripElements : function(stripEl, text, closable, tpl)
38288 var td = document.createElement("li"); // was td..
38291 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38294 stripEl.appendChild(td);
38296 td.className = "x-tabs-closable";
38297 if(!this.closeTpl){
38298 this.closeTpl = new Roo.Template(
38299 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38300 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38301 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38304 var el = this.closeTpl.overwrite(td, {"text": text});
38305 var close = el.getElementsByTagName("div")[0];
38306 var inner = el.getElementsByTagName("em")[0];
38307 return {"el": el, "close": close, "inner": inner};
38310 // not sure what this is..
38311 // if(!this.tabTpl){
38312 //this.tabTpl = new Roo.Template(
38313 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38314 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38316 // this.tabTpl = new Roo.Template(
38317 // '<a href="#">' +
38318 // '<span unselectable="on"' +
38319 // (this.disableTooltips ? '' : ' title="{text}"') +
38320 // ' >{text}</span></a>'
38326 var template = tpl || this.tabTpl || false;
38330 template = new Roo.Template(
38332 '<span unselectable="on"' +
38333 (this.disableTooltips ? '' : ' title="{text}"') +
38334 ' >{text}</span></a>'
38338 switch (typeof(template)) {
38342 template = new Roo.Template(template);
38348 var el = template.overwrite(td, {"text": text});
38350 var inner = el.getElementsByTagName("span")[0];
38352 return {"el": el, "inner": inner};
38360 * @class Roo.TabPanelItem
38361 * @extends Roo.util.Observable
38362 * Represents an individual item (tab plus body) in a TabPanel.
38363 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38364 * @param {String} id The id of this TabPanelItem
38365 * @param {String} text The text for the tab of this TabPanelItem
38366 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38368 Roo.bootstrap.panel.TabItem = function(config){
38370 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38371 * @type Roo.TabPanel
38373 this.tabPanel = config.panel;
38375 * The id for this TabPanelItem
38378 this.id = config.id;
38380 this.disabled = false;
38382 this.text = config.text;
38384 this.loaded = false;
38385 this.closable = config.closable;
38388 * The body element for this TabPanelItem.
38389 * @type Roo.Element
38391 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38392 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38393 this.bodyEl.setStyle("display", "block");
38394 this.bodyEl.setStyle("zoom", "1");
38395 //this.hideAction();
38397 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38399 this.el = Roo.get(els.el);
38400 this.inner = Roo.get(els.inner, true);
38401 this.textEl = Roo.get(this.el.dom.firstChild, true);
38402 this.pnode = Roo.get(els.el.parentNode, true);
38403 // this.el.on("mousedown", this.onTabMouseDown, this);
38404 this.el.on("click", this.onTabClick, this);
38406 if(config.closable){
38407 var c = Roo.get(els.close, true);
38408 c.dom.title = this.closeText;
38409 c.addClassOnOver("close-over");
38410 c.on("click", this.closeClick, this);
38416 * Fires when this tab becomes the active tab.
38417 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38418 * @param {Roo.TabPanelItem} this
38422 * @event beforeclose
38423 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38424 * @param {Roo.TabPanelItem} this
38425 * @param {Object} e Set cancel to true on this object to cancel the close.
38427 "beforeclose": true,
38430 * Fires when this tab is closed.
38431 * @param {Roo.TabPanelItem} this
38435 * @event deactivate
38436 * Fires when this tab is no longer the active tab.
38437 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38438 * @param {Roo.TabPanelItem} this
38440 "deactivate" : true
38442 this.hidden = false;
38444 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38447 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38449 purgeListeners : function(){
38450 Roo.util.Observable.prototype.purgeListeners.call(this);
38451 this.el.removeAllListeners();
38454 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38457 this.pnode.addClass("active");
38460 this.tabPanel.stripWrap.repaint();
38462 this.fireEvent("activate", this.tabPanel, this);
38466 * Returns true if this tab is the active tab.
38467 * @return {Boolean}
38469 isActive : function(){
38470 return this.tabPanel.getActiveTab() == this;
38474 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38477 this.pnode.removeClass("active");
38479 this.fireEvent("deactivate", this.tabPanel, this);
38482 hideAction : function(){
38483 this.bodyEl.hide();
38484 this.bodyEl.setStyle("position", "absolute");
38485 this.bodyEl.setLeft("-20000px");
38486 this.bodyEl.setTop("-20000px");
38489 showAction : function(){
38490 this.bodyEl.setStyle("position", "relative");
38491 this.bodyEl.setTop("");
38492 this.bodyEl.setLeft("");
38493 this.bodyEl.show();
38497 * Set the tooltip for the tab.
38498 * @param {String} tooltip The tab's tooltip
38500 setTooltip : function(text){
38501 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38502 this.textEl.dom.qtip = text;
38503 this.textEl.dom.removeAttribute('title');
38505 this.textEl.dom.title = text;
38509 onTabClick : function(e){
38510 e.preventDefault();
38511 this.tabPanel.activate(this.id);
38514 onTabMouseDown : function(e){
38515 e.preventDefault();
38516 this.tabPanel.activate(this.id);
38519 getWidth : function(){
38520 return this.inner.getWidth();
38523 setWidth : function(width){
38524 var iwidth = width - this.pnode.getPadding("lr");
38525 this.inner.setWidth(iwidth);
38526 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38527 this.pnode.setWidth(width);
38531 * Show or hide the tab
38532 * @param {Boolean} hidden True to hide or false to show.
38534 setHidden : function(hidden){
38535 this.hidden = hidden;
38536 this.pnode.setStyle("display", hidden ? "none" : "");
38540 * Returns true if this tab is "hidden"
38541 * @return {Boolean}
38543 isHidden : function(){
38544 return this.hidden;
38548 * Returns the text for this tab
38551 getText : function(){
38555 autoSize : function(){
38556 //this.el.beginMeasure();
38557 this.textEl.setWidth(1);
38559 * #2804 [new] Tabs in Roojs
38560 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38562 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38563 //this.el.endMeasure();
38567 * Sets the text for the tab (Note: this also sets the tooltip text)
38568 * @param {String} text The tab's text and tooltip
38570 setText : function(text){
38572 this.textEl.update(text);
38573 this.setTooltip(text);
38574 //if(!this.tabPanel.resizeTabs){
38575 // this.autoSize();
38579 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38581 activate : function(){
38582 this.tabPanel.activate(this.id);
38586 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38588 disable : function(){
38589 if(this.tabPanel.active != this){
38590 this.disabled = true;
38591 this.pnode.addClass("disabled");
38596 * Enables this TabPanelItem if it was previously disabled.
38598 enable : function(){
38599 this.disabled = false;
38600 this.pnode.removeClass("disabled");
38604 * Sets the content for this TabPanelItem.
38605 * @param {String} content The content
38606 * @param {Boolean} loadScripts true to look for and load scripts
38608 setContent : function(content, loadScripts){
38609 this.bodyEl.update(content, loadScripts);
38613 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38614 * @return {Roo.UpdateManager} The UpdateManager
38616 getUpdateManager : function(){
38617 return this.bodyEl.getUpdateManager();
38621 * Set a URL to be used to load the content for this TabPanelItem.
38622 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38623 * @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)
38624 * @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)
38625 * @return {Roo.UpdateManager} The UpdateManager
38627 setUrl : function(url, params, loadOnce){
38628 if(this.refreshDelegate){
38629 this.un('activate', this.refreshDelegate);
38631 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38632 this.on("activate", this.refreshDelegate);
38633 return this.bodyEl.getUpdateManager();
38637 _handleRefresh : function(url, params, loadOnce){
38638 if(!loadOnce || !this.loaded){
38639 var updater = this.bodyEl.getUpdateManager();
38640 updater.update(url, params, this._setLoaded.createDelegate(this));
38645 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38646 * Will fail silently if the setUrl method has not been called.
38647 * This does not activate the panel, just updates its content.
38649 refresh : function(){
38650 if(this.refreshDelegate){
38651 this.loaded = false;
38652 this.refreshDelegate();
38657 _setLoaded : function(){
38658 this.loaded = true;
38662 closeClick : function(e){
38665 this.fireEvent("beforeclose", this, o);
38666 if(o.cancel !== true){
38667 this.tabPanel.removeTab(this.id);
38671 * The text displayed in the tooltip for the close icon.
38674 closeText : "Close this tab"
38677 * This script refer to:
38678 * Title: International Telephone Input
38679 * Author: Jack O'Connor
38680 * Code version: v12.1.12
38681 * Availability: https://github.com/jackocnr/intl-tel-input.git
38684 Roo.bootstrap.PhoneInputData = function() {
38687 "Afghanistan (افغانستان)",
38692 "Albania (Shqipëri)",
38697 "Algeria (الجزائر)",
38722 "Antigua and Barbuda",
38732 "Armenia (Հայաստան)",
38748 "Austria (Österreich)",
38753 "Azerbaijan (Azərbaycan)",
38763 "Bahrain (البحرين)",
38768 "Bangladesh (বাংলাদেশ)",
38778 "Belarus (Беларусь)",
38783 "Belgium (België)",
38813 "Bosnia and Herzegovina (Босна и Херцеговина)",
38828 "British Indian Ocean Territory",
38833 "British Virgin Islands",
38843 "Bulgaria (България)",
38853 "Burundi (Uburundi)",
38858 "Cambodia (កម្ពុជា)",
38863 "Cameroon (Cameroun)",
38872 ["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"]
38875 "Cape Verde (Kabu Verdi)",
38880 "Caribbean Netherlands",
38891 "Central African Republic (République centrafricaine)",
38911 "Christmas Island",
38917 "Cocos (Keeling) Islands",
38928 "Comoros (جزر القمر)",
38933 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38938 "Congo (Republic) (Congo-Brazzaville)",
38958 "Croatia (Hrvatska)",
38979 "Czech Republic (Česká republika)",
38984 "Denmark (Danmark)",
38999 "Dominican Republic (República Dominicana)",
39003 ["809", "829", "849"]
39021 "Equatorial Guinea (Guinea Ecuatorial)",
39041 "Falkland Islands (Islas Malvinas)",
39046 "Faroe Islands (Føroyar)",
39067 "French Guiana (Guyane française)",
39072 "French Polynesia (Polynésie française)",
39087 "Georgia (საქართველო)",
39092 "Germany (Deutschland)",
39112 "Greenland (Kalaallit Nunaat)",
39149 "Guinea-Bissau (Guiné Bissau)",
39174 "Hungary (Magyarország)",
39179 "Iceland (Ísland)",
39199 "Iraq (العراق)",
39215 "Israel (ישראל)",
39242 "Jordan (الأردن)",
39247 "Kazakhstan (Казахстан)",
39268 "Kuwait (الكويت)",
39273 "Kyrgyzstan (Кыргызстан)",
39283 "Latvia (Latvija)",
39288 "Lebanon (لبنان)",
39303 "Libya (ليبيا)",
39313 "Lithuania (Lietuva)",
39328 "Macedonia (FYROM) (Македонија)",
39333 "Madagascar (Madagasikara)",
39363 "Marshall Islands",
39373 "Mauritania (موريتانيا)",
39378 "Mauritius (Moris)",
39399 "Moldova (Republica Moldova)",
39409 "Mongolia (Монгол)",
39414 "Montenegro (Crna Gora)",
39424 "Morocco (المغرب)",
39430 "Mozambique (Moçambique)",
39435 "Myanmar (Burma) (မြန်မာ)",
39440 "Namibia (Namibië)",
39455 "Netherlands (Nederland)",
39460 "New Caledonia (Nouvelle-Calédonie)",
39495 "North Korea (조선 민주주의 인민 공화국)",
39500 "Northern Mariana Islands",
39516 "Pakistan (پاکستان)",
39526 "Palestine (فلسطين)",
39536 "Papua New Guinea",
39578 "Réunion (La Réunion)",
39584 "Romania (România)",
39600 "Saint Barthélemy",
39611 "Saint Kitts and Nevis",
39621 "Saint Martin (Saint-Martin (partie française))",
39627 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39632 "Saint Vincent and the Grenadines",
39647 "São Tomé and Príncipe (São Tomé e Príncipe)",
39652 "Saudi Arabia (المملكة العربية السعودية)",
39657 "Senegal (Sénégal)",
39687 "Slovakia (Slovensko)",
39692 "Slovenia (Slovenija)",
39702 "Somalia (Soomaaliya)",
39712 "South Korea (대한민국)",
39717 "South Sudan (جنوب السودان)",
39727 "Sri Lanka (ශ්රී ලංකාව)",
39732 "Sudan (السودان)",
39742 "Svalbard and Jan Mayen",
39753 "Sweden (Sverige)",
39758 "Switzerland (Schweiz)",
39763 "Syria (سوريا)",
39808 "Trinidad and Tobago",
39813 "Tunisia (تونس)",
39818 "Turkey (Türkiye)",
39828 "Turks and Caicos Islands",
39838 "U.S. Virgin Islands",
39848 "Ukraine (Україна)",
39853 "United Arab Emirates (الإمارات العربية المتحدة)",
39875 "Uzbekistan (Oʻzbekiston)",
39885 "Vatican City (Città del Vaticano)",
39896 "Vietnam (Việt Nam)",
39901 "Wallis and Futuna (Wallis-et-Futuna)",
39906 "Western Sahara (الصحراء الغربية)",
39912 "Yemen (اليمن)",
39936 * This script refer to:
39937 * Title: International Telephone Input
39938 * Author: Jack O'Connor
39939 * Code version: v12.1.12
39940 * Availability: https://github.com/jackocnr/intl-tel-input.git
39944 * @class Roo.bootstrap.PhoneInput
39945 * @extends Roo.bootstrap.TriggerField
39946 * An input with International dial-code selection
39948 * @cfg {String} defaultDialCode default '+852'
39949 * @cfg {Array} preferedCountries default []
39952 * Create a new PhoneInput.
39953 * @param {Object} config Configuration options
39956 Roo.bootstrap.PhoneInput = function(config) {
39957 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39960 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39962 listWidth: undefined,
39964 selectedClass: 'active',
39966 invalidClass : "has-warning",
39968 validClass: 'has-success',
39970 allowed: '0123456789',
39975 * @cfg {String} defaultDialCode The default dial code when initializing the input
39977 defaultDialCode: '+852',
39980 * @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
39982 preferedCountries: false,
39984 getAutoCreate : function()
39986 var data = Roo.bootstrap.PhoneInputData();
39987 var align = this.labelAlign || this.parentLabelAlign();
39990 this.allCountries = [];
39991 this.dialCodeMapping = [];
39993 for (var i = 0; i < data.length; i++) {
39995 this.allCountries[i] = {
39999 priority: c[3] || 0,
40000 areaCodes: c[4] || null
40002 this.dialCodeMapping[c[2]] = {
40005 priority: c[3] || 0,
40006 areaCodes: c[4] || null
40018 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40019 maxlength: this.max_length,
40020 cls : 'form-control tel-input',
40021 autocomplete: 'new-password'
40024 var hiddenInput = {
40027 cls: 'hidden-tel-input'
40031 hiddenInput.name = this.name;
40034 if (this.disabled) {
40035 input.disabled = true;
40038 var flag_container = {
40055 cls: this.hasFeedback ? 'has-feedback' : '',
40061 cls: 'dial-code-holder',
40068 cls: 'roo-select2-container input-group',
40075 if (this.fieldLabel.length) {
40078 tooltip: 'This field is required'
40084 cls: 'control-label',
40090 html: this.fieldLabel
40093 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40099 if(this.indicatorpos == 'right') {
40100 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40107 if(align == 'left') {
40115 if(this.labelWidth > 12){
40116 label.style = "width: " + this.labelWidth + 'px';
40118 if(this.labelWidth < 13 && this.labelmd == 0){
40119 this.labelmd = this.labelWidth;
40121 if(this.labellg > 0){
40122 label.cls += ' col-lg-' + this.labellg;
40123 input.cls += ' col-lg-' + (12 - this.labellg);
40125 if(this.labelmd > 0){
40126 label.cls += ' col-md-' + this.labelmd;
40127 container.cls += ' col-md-' + (12 - this.labelmd);
40129 if(this.labelsm > 0){
40130 label.cls += ' col-sm-' + this.labelsm;
40131 container.cls += ' col-sm-' + (12 - this.labelsm);
40133 if(this.labelxs > 0){
40134 label.cls += ' col-xs-' + this.labelxs;
40135 container.cls += ' col-xs-' + (12 - this.labelxs);
40145 var settings = this;
40147 ['xs','sm','md','lg'].map(function(size){
40148 if (settings[size]) {
40149 cfg.cls += ' col-' + size + '-' + settings[size];
40153 this.store = new Roo.data.Store({
40154 proxy : new Roo.data.MemoryProxy({}),
40155 reader : new Roo.data.JsonReader({
40166 'name' : 'dialCode',
40170 'name' : 'priority',
40174 'name' : 'areaCodes',
40181 if(!this.preferedCountries) {
40182 this.preferedCountries = [
40189 var p = this.preferedCountries.reverse();
40192 for (var i = 0; i < p.length; i++) {
40193 for (var j = 0; j < this.allCountries.length; j++) {
40194 if(this.allCountries[j].iso2 == p[i]) {
40195 var t = this.allCountries[j];
40196 this.allCountries.splice(j,1);
40197 this.allCountries.unshift(t);
40203 this.store.proxy.data = {
40205 data: this.allCountries
40211 initEvents : function()
40214 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40216 this.indicator = this.indicatorEl();
40217 this.flag = this.flagEl();
40218 this.dialCodeHolder = this.dialCodeHolderEl();
40220 this.trigger = this.el.select('div.flag-box',true).first();
40221 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40226 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40227 _this.list.setWidth(lw);
40230 this.list.on('mouseover', this.onViewOver, this);
40231 this.list.on('mousemove', this.onViewMove, this);
40232 this.inputEl().on("keyup", this.onKeyUp, this);
40233 this.inputEl().on("keypress", this.onKeyPress, this);
40235 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40237 this.view = new Roo.View(this.list, this.tpl, {
40238 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40241 this.view.on('click', this.onViewClick, this);
40242 this.setValue(this.defaultDialCode);
40245 onTriggerClick : function(e)
40247 Roo.log('trigger click');
40252 if(this.isExpanded()){
40254 this.hasFocus = false;
40256 this.store.load({});
40257 this.hasFocus = true;
40262 isExpanded : function()
40264 return this.list.isVisible();
40267 collapse : function()
40269 if(!this.isExpanded()){
40273 Roo.get(document).un('mousedown', this.collapseIf, this);
40274 Roo.get(document).un('mousewheel', this.collapseIf, this);
40275 this.fireEvent('collapse', this);
40279 expand : function()
40283 if(this.isExpanded() || !this.hasFocus){
40287 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40288 this.list.setWidth(lw);
40291 this.restrictHeight();
40293 Roo.get(document).on('mousedown', this.collapseIf, this);
40294 Roo.get(document).on('mousewheel', this.collapseIf, this);
40296 this.fireEvent('expand', this);
40299 restrictHeight : function()
40301 this.list.alignTo(this.inputEl(), this.listAlign);
40302 this.list.alignTo(this.inputEl(), this.listAlign);
40305 onViewOver : function(e, t)
40307 if(this.inKeyMode){
40310 var item = this.view.findItemFromChild(t);
40313 var index = this.view.indexOf(item);
40314 this.select(index, false);
40319 onViewClick : function(view, doFocus, el, e)
40321 var index = this.view.getSelectedIndexes()[0];
40323 var r = this.store.getAt(index);
40326 this.onSelect(r, index);
40328 if(doFocus !== false && !this.blockFocus){
40329 this.inputEl().focus();
40333 onViewMove : function(e, t)
40335 this.inKeyMode = false;
40338 select : function(index, scrollIntoView)
40340 this.selectedIndex = index;
40341 this.view.select(index);
40342 if(scrollIntoView !== false){
40343 var el = this.view.getNode(index);
40345 this.list.scrollChildIntoView(el, false);
40350 createList : function()
40352 this.list = Roo.get(document.body).createChild({
40354 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40355 style: 'display:none'
40358 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40361 collapseIf : function(e)
40363 var in_combo = e.within(this.el);
40364 var in_list = e.within(this.list);
40365 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40367 if (in_combo || in_list || is_list) {
40373 onSelect : function(record, index)
40375 if(this.fireEvent('beforeselect', this, record, index) !== false){
40377 this.setFlagClass(record.data.iso2);
40378 this.setDialCode(record.data.dialCode);
40379 this.hasFocus = false;
40381 this.fireEvent('select', this, record, index);
40385 flagEl : function()
40387 var flag = this.el.select('div.flag',true).first();
40394 dialCodeHolderEl : function()
40396 var d = this.el.select('input.dial-code-holder',true).first();
40403 setDialCode : function(v)
40405 this.dialCodeHolder.dom.value = '+'+v;
40408 setFlagClass : function(n)
40410 this.flag.dom.className = 'flag '+n;
40413 getValue : function()
40415 var v = this.inputEl().getValue();
40416 if(this.dialCodeHolder) {
40417 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40422 setValue : function(v)
40424 var d = this.getDialCode(v);
40426 //invalid dial code
40427 if(v.length == 0 || !d || d.length == 0) {
40429 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40430 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40436 this.setFlagClass(this.dialCodeMapping[d].iso2);
40437 this.setDialCode(d);
40438 this.inputEl().dom.value = v.replace('+'+d,'');
40439 this.hiddenEl().dom.value = this.getValue();
40444 getDialCode : function(v)
40448 if (v.length == 0) {
40449 return this.dialCodeHolder.dom.value;
40453 if (v.charAt(0) != "+") {
40456 var numericChars = "";
40457 for (var i = 1; i < v.length; i++) {
40458 var c = v.charAt(i);
40461 if (this.dialCodeMapping[numericChars]) {
40462 dialCode = v.substr(1, i);
40464 if (numericChars.length == 4) {
40474 this.setValue(this.defaultDialCode);
40478 hiddenEl : function()
40480 return this.el.select('input.hidden-tel-input',true).first();
40483 // after setting val
40484 onKeyUp : function(e){
40485 this.setValue(this.getValue());
40488 onKeyPress : function(e){
40489 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40496 * @class Roo.bootstrap.MoneyField
40497 * @extends Roo.bootstrap.ComboBox
40498 * Bootstrap MoneyField class
40501 * Create a new MoneyField.
40502 * @param {Object} config Configuration options
40505 Roo.bootstrap.MoneyField = function(config) {
40507 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40511 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40514 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40516 allowDecimals : true,
40518 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40520 decimalSeparator : ".",
40522 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40524 decimalPrecision : 0,
40526 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40528 allowNegative : true,
40530 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40534 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40536 minValue : Number.NEGATIVE_INFINITY,
40538 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40540 maxValue : Number.MAX_VALUE,
40542 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40544 minText : "The minimum value for this field is {0}",
40546 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40548 maxText : "The maximum value for this field is {0}",
40550 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40551 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40553 nanText : "{0} is not a valid number",
40555 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40559 * @cfg {String} defaults currency of the MoneyField
40560 * value should be in lkey
40562 defaultCurrency : false,
40564 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40566 thousandsDelimiter : false,
40568 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40579 getAutoCreate : function()
40581 var align = this.labelAlign || this.parentLabelAlign();
40593 cls : 'form-control roo-money-amount-input',
40594 autocomplete: 'new-password'
40597 var hiddenInput = {
40601 cls: 'hidden-number-input'
40604 if(this.max_length) {
40605 input.maxlength = this.max_length;
40609 hiddenInput.name = this.name;
40612 if (this.disabled) {
40613 input.disabled = true;
40616 var clg = 12 - this.inputlg;
40617 var cmd = 12 - this.inputmd;
40618 var csm = 12 - this.inputsm;
40619 var cxs = 12 - this.inputxs;
40623 cls : 'row roo-money-field',
40627 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40631 cls: 'roo-select2-container input-group',
40635 cls : 'form-control roo-money-currency-input',
40636 autocomplete: 'new-password',
40638 name : this.currencyName
40642 cls : 'input-group-addon',
40656 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40660 cls: this.hasFeedback ? 'has-feedback' : '',
40671 if (this.fieldLabel.length) {
40674 tooltip: 'This field is required'
40680 cls: 'control-label',
40686 html: this.fieldLabel
40689 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40695 if(this.indicatorpos == 'right') {
40696 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40703 if(align == 'left') {
40711 if(this.labelWidth > 12){
40712 label.style = "width: " + this.labelWidth + 'px';
40714 if(this.labelWidth < 13 && this.labelmd == 0){
40715 this.labelmd = this.labelWidth;
40717 if(this.labellg > 0){
40718 label.cls += ' col-lg-' + this.labellg;
40719 input.cls += ' col-lg-' + (12 - this.labellg);
40721 if(this.labelmd > 0){
40722 label.cls += ' col-md-' + this.labelmd;
40723 container.cls += ' col-md-' + (12 - this.labelmd);
40725 if(this.labelsm > 0){
40726 label.cls += ' col-sm-' + this.labelsm;
40727 container.cls += ' col-sm-' + (12 - this.labelsm);
40729 if(this.labelxs > 0){
40730 label.cls += ' col-xs-' + this.labelxs;
40731 container.cls += ' col-xs-' + (12 - this.labelxs);
40742 var settings = this;
40744 ['xs','sm','md','lg'].map(function(size){
40745 if (settings[size]) {
40746 cfg.cls += ' col-' + size + '-' + settings[size];
40753 initEvents : function()
40755 this.indicator = this.indicatorEl();
40757 this.initCurrencyEvent();
40759 this.initNumberEvent();
40762 initCurrencyEvent : function()
40765 throw "can not find store for combo";
40768 this.store = Roo.factory(this.store, Roo.data);
40769 this.store.parent = this;
40773 this.triggerEl = this.el.select('.input-group-addon', true).first();
40775 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40780 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40781 _this.list.setWidth(lw);
40784 this.list.on('mouseover', this.onViewOver, this);
40785 this.list.on('mousemove', this.onViewMove, this);
40786 this.list.on('scroll', this.onViewScroll, this);
40789 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40792 this.view = new Roo.View(this.list, this.tpl, {
40793 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40796 this.view.on('click', this.onViewClick, this);
40798 this.store.on('beforeload', this.onBeforeLoad, this);
40799 this.store.on('load', this.onLoad, this);
40800 this.store.on('loadexception', this.onLoadException, this);
40802 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40803 "up" : function(e){
40804 this.inKeyMode = true;
40808 "down" : function(e){
40809 if(!this.isExpanded()){
40810 this.onTriggerClick();
40812 this.inKeyMode = true;
40817 "enter" : function(e){
40820 if(this.fireEvent("specialkey", this, e)){
40821 this.onViewClick(false);
40827 "esc" : function(e){
40831 "tab" : function(e){
40834 if(this.fireEvent("specialkey", this, e)){
40835 this.onViewClick(false);
40843 doRelay : function(foo, bar, hname){
40844 if(hname == 'down' || this.scope.isExpanded()){
40845 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40853 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40857 initNumberEvent : function(e)
40859 this.inputEl().on("keydown" , this.fireKey, this);
40860 this.inputEl().on("focus", this.onFocus, this);
40861 this.inputEl().on("blur", this.onBlur, this);
40863 this.inputEl().relayEvent('keyup', this);
40865 if(this.indicator){
40866 this.indicator.addClass('invisible');
40869 this.originalValue = this.getValue();
40871 if(this.validationEvent == 'keyup'){
40872 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40873 this.inputEl().on('keyup', this.filterValidation, this);
40875 else if(this.validationEvent !== false){
40876 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40879 if(this.selectOnFocus){
40880 this.on("focus", this.preFocus, this);
40883 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40884 this.inputEl().on("keypress", this.filterKeys, this);
40886 this.inputEl().relayEvent('keypress', this);
40889 var allowed = "0123456789";
40891 if(this.allowDecimals){
40892 allowed += this.decimalSeparator;
40895 if(this.allowNegative){
40899 if(this.thousandsDelimiter) {
40903 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40905 var keyPress = function(e){
40907 var k = e.getKey();
40909 var c = e.getCharCode();
40912 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40913 allowed.indexOf(String.fromCharCode(c)) === -1
40919 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40923 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40928 this.inputEl().on("keypress", keyPress, this);
40932 onTriggerClick : function(e)
40939 this.loadNext = false;
40941 if(this.isExpanded()){
40946 this.hasFocus = true;
40948 if(this.triggerAction == 'all') {
40949 this.doQuery(this.allQuery, true);
40953 this.doQuery(this.getRawValue());
40956 getCurrency : function()
40958 var v = this.currencyEl().getValue();
40963 restrictHeight : function()
40965 this.list.alignTo(this.currencyEl(), this.listAlign);
40966 this.list.alignTo(this.currencyEl(), this.listAlign);
40969 onViewClick : function(view, doFocus, el, e)
40971 var index = this.view.getSelectedIndexes()[0];
40973 var r = this.store.getAt(index);
40976 this.onSelect(r, index);
40980 onSelect : function(record, index){
40982 if(this.fireEvent('beforeselect', this, record, index) !== false){
40984 this.setFromCurrencyData(index > -1 ? record.data : false);
40988 this.fireEvent('select', this, record, index);
40992 setFromCurrencyData : function(o)
40996 this.lastCurrency = o;
40998 if (this.currencyField) {
40999 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41001 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41004 this.lastSelectionText = currency;
41006 //setting default currency
41007 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41008 this.setCurrency(this.defaultCurrency);
41012 this.setCurrency(currency);
41015 setFromData : function(o)
41019 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41021 this.setFromCurrencyData(c);
41026 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41028 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41031 this.setValue(value);
41035 setCurrency : function(v)
41037 this.currencyValue = v;
41040 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41045 setValue : function(v)
41047 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41053 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41055 this.inputEl().dom.value = (v == '') ? '' :
41056 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41058 if(!this.allowZero && v === '0') {
41059 this.hiddenEl().dom.value = '';
41060 this.inputEl().dom.value = '';
41067 getRawValue : function()
41069 var v = this.inputEl().getValue();
41074 getValue : function()
41076 return this.fixPrecision(this.parseValue(this.getRawValue()));
41079 parseValue : function(value)
41081 if(this.thousandsDelimiter) {
41083 r = new RegExp(",", "g");
41084 value = value.replace(r, "");
41087 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41088 return isNaN(value) ? '' : value;
41092 fixPrecision : function(value)
41094 if(this.thousandsDelimiter) {
41096 r = new RegExp(",", "g");
41097 value = value.replace(r, "");
41100 var nan = isNaN(value);
41102 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41103 return nan ? '' : value;
41105 return parseFloat(value).toFixed(this.decimalPrecision);
41108 decimalPrecisionFcn : function(v)
41110 return Math.floor(v);
41113 validateValue : function(value)
41115 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41119 var num = this.parseValue(value);
41122 this.markInvalid(String.format(this.nanText, value));
41126 if(num < this.minValue){
41127 this.markInvalid(String.format(this.minText, this.minValue));
41131 if(num > this.maxValue){
41132 this.markInvalid(String.format(this.maxText, this.maxValue));
41139 validate : function()
41141 if(this.disabled || this.allowBlank){
41146 var currency = this.getCurrency();
41148 if(this.validateValue(this.getRawValue()) && currency.length){
41153 this.markInvalid();
41157 getName: function()
41162 beforeBlur : function()
41168 var v = this.parseValue(this.getRawValue());
41175 onBlur : function()
41179 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41180 //this.el.removeClass(this.focusClass);
41183 this.hasFocus = false;
41185 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41189 var v = this.getValue();
41191 if(String(v) !== String(this.startValue)){
41192 this.fireEvent('change', this, v, this.startValue);
41195 this.fireEvent("blur", this);
41198 inputEl : function()
41200 return this.el.select('.roo-money-amount-input', true).first();
41203 currencyEl : function()
41205 return this.el.select('.roo-money-currency-input', true).first();
41208 hiddenEl : function()
41210 return this.el.select('input.hidden-number-input',true).first();