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',
13359 // cls: 'typeahead typeahead-long dropdown-menu',
13360 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13365 if(this.hasFeedback && !this.allowBlank){
13369 cls: 'glyphicon form-control-feedback'
13372 combobox.cn.push(feedback);
13377 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13378 tooltip : 'This field is required'
13380 if (Roo.bootstrap.version == 4) {
13383 style : 'display:none'
13386 if (align ==='left' && this.fieldLabel.length) {
13388 cfg.cls += ' roo-form-group-label-left row';
13395 cls : 'control-label col-form-label',
13396 html : this.fieldLabel
13408 var labelCfg = cfg.cn[1];
13409 var contentCfg = cfg.cn[2];
13412 if(this.indicatorpos == 'right'){
13418 cls : 'control-label col-form-label',
13422 html : this.fieldLabel
13438 labelCfg = cfg.cn[0];
13439 contentCfg = cfg.cn[1];
13443 if(this.labelWidth > 12){
13444 labelCfg.style = "width: " + this.labelWidth + 'px';
13447 if(this.labelWidth < 13 && this.labelmd == 0){
13448 this.labelmd = this.labelWidth;
13451 if(this.labellg > 0){
13452 labelCfg.cls += ' col-lg-' + this.labellg;
13453 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13456 if(this.labelmd > 0){
13457 labelCfg.cls += ' col-md-' + this.labelmd;
13458 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13461 if(this.labelsm > 0){
13462 labelCfg.cls += ' col-sm-' + this.labelsm;
13463 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13466 if(this.labelxs > 0){
13467 labelCfg.cls += ' col-xs-' + this.labelxs;
13468 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13472 } else if ( this.fieldLabel.length) {
13473 // Roo.log(" label");
13478 //cls : 'input-group-addon',
13479 html : this.fieldLabel
13484 if(this.indicatorpos == 'right'){
13488 //cls : 'input-group-addon',
13489 html : this.fieldLabel
13499 // Roo.log(" no label && no align");
13506 ['xs','sm','md','lg'].map(function(size){
13507 if (settings[size]) {
13508 cfg.cls += ' col-' + size + '-' + settings[size];
13516 _initEventsCalled : false,
13519 initEvents: function()
13521 if (this._initEventsCalled) { // as we call render... prevent looping...
13524 this._initEventsCalled = true;
13527 throw "can not find store for combo";
13530 this.indicator = this.indicatorEl();
13532 this.store = Roo.factory(this.store, Roo.data);
13533 this.store.parent = this;
13535 // if we are building from html. then this element is so complex, that we can not really
13536 // use the rendered HTML.
13537 // so we have to trash and replace the previous code.
13538 if (Roo.XComponent.build_from_html) {
13539 // remove this element....
13540 var e = this.el.dom, k=0;
13541 while (e ) { e = e.previousSibling; ++k;}
13546 this.rendered = false;
13548 this.render(this.parent().getChildContainer(true), k);
13551 if(Roo.isIOS && this.useNativeIOS){
13552 this.initIOSView();
13560 if(Roo.isTouch && this.mobileTouchView){
13561 this.initTouchView();
13566 this.initTickableEvents();
13570 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13572 if(this.hiddenName){
13574 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13576 this.hiddenField.dom.value =
13577 this.hiddenValue !== undefined ? this.hiddenValue :
13578 this.value !== undefined ? this.value : '';
13580 // prevent input submission
13581 this.el.dom.removeAttribute('name');
13582 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13587 // this.el.dom.setAttribute('autocomplete', 'off');
13590 var cls = 'x-combo-list';
13592 //this.list = new Roo.Layer({
13593 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13599 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13600 _this.list.setWidth(lw);
13603 this.list.on('mouseover', this.onViewOver, this);
13604 this.list.on('mousemove', this.onViewMove, this);
13605 this.list.on('scroll', this.onViewScroll, this);
13608 this.list.swallowEvent('mousewheel');
13609 this.assetHeight = 0;
13612 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13613 this.assetHeight += this.header.getHeight();
13616 this.innerList = this.list.createChild({cls:cls+'-inner'});
13617 this.innerList.on('mouseover', this.onViewOver, this);
13618 this.innerList.on('mousemove', this.onViewMove, this);
13619 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13621 if(this.allowBlank && !this.pageSize && !this.disableClear){
13622 this.footer = this.list.createChild({cls:cls+'-ft'});
13623 this.pageTb = new Roo.Toolbar(this.footer);
13627 this.footer = this.list.createChild({cls:cls+'-ft'});
13628 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13629 {pageSize: this.pageSize});
13633 if (this.pageTb && this.allowBlank && !this.disableClear) {
13635 this.pageTb.add(new Roo.Toolbar.Fill(), {
13636 cls: 'x-btn-icon x-btn-clear',
13638 handler: function()
13641 _this.clearValue();
13642 _this.onSelect(false, -1);
13647 this.assetHeight += this.footer.getHeight();
13652 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13655 this.view = new Roo.View(this.list, this.tpl, {
13656 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13658 //this.view.wrapEl.setDisplayed(false);
13659 this.view.on('click', this.onViewClick, this);
13662 this.store.on('beforeload', this.onBeforeLoad, this);
13663 this.store.on('load', this.onLoad, this);
13664 this.store.on('loadexception', this.onLoadException, this);
13666 if(this.resizable){
13667 this.resizer = new Roo.Resizable(this.list, {
13668 pinned:true, handles:'se'
13670 this.resizer.on('resize', function(r, w, h){
13671 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13672 this.listWidth = w;
13673 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13674 this.restrictHeight();
13676 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13679 if(!this.editable){
13680 this.editable = true;
13681 this.setEditable(false);
13686 if (typeof(this.events.add.listeners) != 'undefined') {
13688 this.addicon = this.wrap.createChild(
13689 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13691 this.addicon.on('click', function(e) {
13692 this.fireEvent('add', this);
13695 if (typeof(this.events.edit.listeners) != 'undefined') {
13697 this.editicon = this.wrap.createChild(
13698 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13699 if (this.addicon) {
13700 this.editicon.setStyle('margin-left', '40px');
13702 this.editicon.on('click', function(e) {
13704 // we fire even if inothing is selected..
13705 this.fireEvent('edit', this, this.lastData );
13711 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13712 "up" : function(e){
13713 this.inKeyMode = true;
13717 "down" : function(e){
13718 if(!this.isExpanded()){
13719 this.onTriggerClick();
13721 this.inKeyMode = true;
13726 "enter" : function(e){
13727 // this.onViewClick();
13731 if(this.fireEvent("specialkey", this, e)){
13732 this.onViewClick(false);
13738 "esc" : function(e){
13742 "tab" : function(e){
13745 if(this.fireEvent("specialkey", this, e)){
13746 this.onViewClick(false);
13754 doRelay : function(foo, bar, hname){
13755 if(hname == 'down' || this.scope.isExpanded()){
13756 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13765 this.queryDelay = Math.max(this.queryDelay || 10,
13766 this.mode == 'local' ? 10 : 250);
13769 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13771 if(this.typeAhead){
13772 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13774 if(this.editable !== false){
13775 this.inputEl().on("keyup", this.onKeyUp, this);
13777 if(this.forceSelection){
13778 this.inputEl().on('blur', this.doForce, this);
13782 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13783 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13787 initTickableEvents: function()
13791 if(this.hiddenName){
13793 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13795 this.hiddenField.dom.value =
13796 this.hiddenValue !== undefined ? this.hiddenValue :
13797 this.value !== undefined ? this.value : '';
13799 // prevent input submission
13800 this.el.dom.removeAttribute('name');
13801 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13806 // this.list = this.el.select('ul.dropdown-menu',true).first();
13808 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13809 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13810 if(this.triggerList){
13811 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13814 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13815 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13817 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13818 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13820 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13821 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13823 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13824 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13825 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13828 this.cancelBtn.hide();
13833 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13834 _this.list.setWidth(lw);
13837 this.list.on('mouseover', this.onViewOver, this);
13838 this.list.on('mousemove', this.onViewMove, this);
13840 this.list.on('scroll', this.onViewScroll, this);
13843 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13844 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13847 this.view = new Roo.View(this.list, this.tpl, {
13852 selectedClass: this.selectedClass
13855 //this.view.wrapEl.setDisplayed(false);
13856 this.view.on('click', this.onViewClick, this);
13860 this.store.on('beforeload', this.onBeforeLoad, this);
13861 this.store.on('load', this.onLoad, this);
13862 this.store.on('loadexception', this.onLoadException, this);
13865 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13866 "up" : function(e){
13867 this.inKeyMode = true;
13871 "down" : function(e){
13872 this.inKeyMode = true;
13876 "enter" : function(e){
13877 if(this.fireEvent("specialkey", this, e)){
13878 this.onViewClick(false);
13884 "esc" : function(e){
13885 this.onTickableFooterButtonClick(e, false, false);
13888 "tab" : function(e){
13889 this.fireEvent("specialkey", this, e);
13891 this.onTickableFooterButtonClick(e, false, false);
13898 doRelay : function(e, fn, key){
13899 if(this.scope.isExpanded()){
13900 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13909 this.queryDelay = Math.max(this.queryDelay || 10,
13910 this.mode == 'local' ? 10 : 250);
13913 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13915 if(this.typeAhead){
13916 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13919 if(this.editable !== false){
13920 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13923 this.indicator = this.indicatorEl();
13925 if(this.indicator){
13926 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13927 this.indicator.hide();
13932 onDestroy : function(){
13934 this.view.setStore(null);
13935 this.view.el.removeAllListeners();
13936 this.view.el.remove();
13937 this.view.purgeListeners();
13940 this.list.dom.innerHTML = '';
13944 this.store.un('beforeload', this.onBeforeLoad, this);
13945 this.store.un('load', this.onLoad, this);
13946 this.store.un('loadexception', this.onLoadException, this);
13948 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13952 fireKey : function(e){
13953 if(e.isNavKeyPress() && !this.list.isVisible()){
13954 this.fireEvent("specialkey", this, e);
13959 onResize: function(w, h){
13960 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13962 // if(typeof w != 'number'){
13963 // // we do not handle it!?!?
13966 // var tw = this.trigger.getWidth();
13967 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13968 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13970 // this.inputEl().setWidth( this.adjustWidth('input', x));
13972 // //this.trigger.setStyle('left', x+'px');
13974 // if(this.list && this.listWidth === undefined){
13975 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13976 // this.list.setWidth(lw);
13977 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13985 * Allow or prevent the user from directly editing the field text. If false is passed,
13986 * the user will only be able to select from the items defined in the dropdown list. This method
13987 * is the runtime equivalent of setting the 'editable' config option at config time.
13988 * @param {Boolean} value True to allow the user to directly edit the field text
13990 setEditable : function(value){
13991 if(value == this.editable){
13994 this.editable = value;
13996 this.inputEl().dom.setAttribute('readOnly', true);
13997 this.inputEl().on('mousedown', this.onTriggerClick, this);
13998 this.inputEl().addClass('x-combo-noedit');
14000 this.inputEl().dom.setAttribute('readOnly', false);
14001 this.inputEl().un('mousedown', this.onTriggerClick, this);
14002 this.inputEl().removeClass('x-combo-noedit');
14008 onBeforeLoad : function(combo,opts){
14009 if(!this.hasFocus){
14013 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14015 this.restrictHeight();
14016 this.selectedIndex = -1;
14020 onLoad : function(){
14022 this.hasQuery = false;
14024 if(!this.hasFocus){
14028 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14029 this.loading.hide();
14032 if(this.store.getCount() > 0){
14035 this.restrictHeight();
14036 if(this.lastQuery == this.allQuery){
14037 if(this.editable && !this.tickable){
14038 this.inputEl().dom.select();
14042 !this.selectByValue(this.value, true) &&
14045 !this.store.lastOptions ||
14046 typeof(this.store.lastOptions.add) == 'undefined' ||
14047 this.store.lastOptions.add != true
14050 this.select(0, true);
14053 if(this.autoFocus){
14056 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14057 this.taTask.delay(this.typeAheadDelay);
14061 this.onEmptyResults();
14067 onLoadException : function()
14069 this.hasQuery = false;
14071 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14072 this.loading.hide();
14075 if(this.tickable && this.editable){
14080 // only causes errors at present
14081 //Roo.log(this.store.reader.jsonData);
14082 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14084 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14090 onTypeAhead : function(){
14091 if(this.store.getCount() > 0){
14092 var r = this.store.getAt(0);
14093 var newValue = r.data[this.displayField];
14094 var len = newValue.length;
14095 var selStart = this.getRawValue().length;
14097 if(selStart != len){
14098 this.setRawValue(newValue);
14099 this.selectText(selStart, newValue.length);
14105 onSelect : function(record, index){
14107 if(this.fireEvent('beforeselect', this, record, index) !== false){
14109 this.setFromData(index > -1 ? record.data : false);
14112 this.fireEvent('select', this, record, index);
14117 * Returns the currently selected field value or empty string if no value is set.
14118 * @return {String} value The selected value
14120 getValue : function()
14122 if(Roo.isIOS && this.useNativeIOS){
14123 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14127 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14130 if(this.valueField){
14131 return typeof this.value != 'undefined' ? this.value : '';
14133 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14137 getRawValue : function()
14139 if(Roo.isIOS && this.useNativeIOS){
14140 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14143 var v = this.inputEl().getValue();
14149 * Clears any text/value currently set in the field
14151 clearValue : function(){
14153 if(this.hiddenField){
14154 this.hiddenField.dom.value = '';
14157 this.setRawValue('');
14158 this.lastSelectionText = '';
14159 this.lastData = false;
14161 var close = this.closeTriggerEl();
14172 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14173 * will be displayed in the field. If the value does not match the data value of an existing item,
14174 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14175 * Otherwise the field will be blank (although the value will still be set).
14176 * @param {String} value The value to match
14178 setValue : function(v)
14180 if(Roo.isIOS && this.useNativeIOS){
14181 this.setIOSValue(v);
14191 if(this.valueField){
14192 var r = this.findRecord(this.valueField, v);
14194 text = r.data[this.displayField];
14195 }else if(this.valueNotFoundText !== undefined){
14196 text = this.valueNotFoundText;
14199 this.lastSelectionText = text;
14200 if(this.hiddenField){
14201 this.hiddenField.dom.value = v;
14203 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14206 var close = this.closeTriggerEl();
14209 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14215 * @property {Object} the last set data for the element
14220 * Sets the value of the field based on a object which is related to the record format for the store.
14221 * @param {Object} value the value to set as. or false on reset?
14223 setFromData : function(o){
14230 var dv = ''; // display value
14231 var vv = ''; // value value..
14233 if (this.displayField) {
14234 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14236 // this is an error condition!!!
14237 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14240 if(this.valueField){
14241 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14244 var close = this.closeTriggerEl();
14247 if(dv.length || vv * 1 > 0){
14249 this.blockFocus=true;
14255 if(this.hiddenField){
14256 this.hiddenField.dom.value = vv;
14258 this.lastSelectionText = dv;
14259 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14263 // no hidden field.. - we store the value in 'value', but still display
14264 // display field!!!!
14265 this.lastSelectionText = dv;
14266 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14273 reset : function(){
14274 // overridden so that last data is reset..
14281 this.setValue(this.originalValue);
14282 //this.clearInvalid();
14283 this.lastData = false;
14285 this.view.clearSelections();
14291 findRecord : function(prop, value){
14293 if(this.store.getCount() > 0){
14294 this.store.each(function(r){
14295 if(r.data[prop] == value){
14305 getName: function()
14307 // returns hidden if it's set..
14308 if (!this.rendered) {return ''};
14309 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14313 onViewMove : function(e, t){
14314 this.inKeyMode = false;
14318 onViewOver : function(e, t){
14319 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14322 var item = this.view.findItemFromChild(t);
14325 var index = this.view.indexOf(item);
14326 this.select(index, false);
14331 onViewClick : function(view, doFocus, el, e)
14333 var index = this.view.getSelectedIndexes()[0];
14335 var r = this.store.getAt(index);
14339 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14346 Roo.each(this.tickItems, function(v,k){
14348 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14350 _this.tickItems.splice(k, 1);
14352 if(typeof(e) == 'undefined' && view == false){
14353 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14365 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14366 this.tickItems.push(r.data);
14369 if(typeof(e) == 'undefined' && view == false){
14370 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14377 this.onSelect(r, index);
14379 if(doFocus !== false && !this.blockFocus){
14380 this.inputEl().focus();
14385 restrictHeight : function(){
14386 //this.innerList.dom.style.height = '';
14387 //var inner = this.innerList.dom;
14388 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14389 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14390 //this.list.beginUpdate();
14391 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14392 this.list.alignTo(this.inputEl(), this.listAlign);
14393 this.list.alignTo(this.inputEl(), this.listAlign);
14394 //this.list.endUpdate();
14398 onEmptyResults : function(){
14400 if(this.tickable && this.editable){
14401 this.hasFocus = false;
14402 this.restrictHeight();
14410 * Returns true if the dropdown list is expanded, else false.
14412 isExpanded : function(){
14413 return this.list.isVisible();
14417 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14418 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14419 * @param {String} value The data value of the item to select
14420 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14421 * selected item if it is not currently in view (defaults to true)
14422 * @return {Boolean} True if the value matched an item in the list, else false
14424 selectByValue : function(v, scrollIntoView){
14425 if(v !== undefined && v !== null){
14426 var r = this.findRecord(this.valueField || this.displayField, v);
14428 this.select(this.store.indexOf(r), scrollIntoView);
14436 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14437 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14438 * @param {Number} index The zero-based index of the list item to select
14439 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14440 * selected item if it is not currently in view (defaults to true)
14442 select : function(index, scrollIntoView){
14443 this.selectedIndex = index;
14444 this.view.select(index);
14445 if(scrollIntoView !== false){
14446 var el = this.view.getNode(index);
14448 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14451 this.list.scrollChildIntoView(el, false);
14457 selectNext : function(){
14458 var ct = this.store.getCount();
14460 if(this.selectedIndex == -1){
14462 }else if(this.selectedIndex < ct-1){
14463 this.select(this.selectedIndex+1);
14469 selectPrev : function(){
14470 var ct = this.store.getCount();
14472 if(this.selectedIndex == -1){
14474 }else if(this.selectedIndex != 0){
14475 this.select(this.selectedIndex-1);
14481 onKeyUp : function(e){
14482 if(this.editable !== false && !e.isSpecialKey()){
14483 this.lastKey = e.getKey();
14484 this.dqTask.delay(this.queryDelay);
14489 validateBlur : function(){
14490 return !this.list || !this.list.isVisible();
14494 initQuery : function(){
14496 var v = this.getRawValue();
14498 if(this.tickable && this.editable){
14499 v = this.tickableInputEl().getValue();
14506 doForce : function(){
14507 if(this.inputEl().dom.value.length > 0){
14508 this.inputEl().dom.value =
14509 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14515 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14516 * query allowing the query action to be canceled if needed.
14517 * @param {String} query The SQL query to execute
14518 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14519 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14520 * saved in the current store (defaults to false)
14522 doQuery : function(q, forceAll){
14524 if(q === undefined || q === null){
14529 forceAll: forceAll,
14533 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14538 forceAll = qe.forceAll;
14539 if(forceAll === true || (q.length >= this.minChars)){
14541 this.hasQuery = true;
14543 if(this.lastQuery != q || this.alwaysQuery){
14544 this.lastQuery = q;
14545 if(this.mode == 'local'){
14546 this.selectedIndex = -1;
14548 this.store.clearFilter();
14551 if(this.specialFilter){
14552 this.fireEvent('specialfilter', this);
14557 this.store.filter(this.displayField, q);
14560 this.store.fireEvent("datachanged", this.store);
14567 this.store.baseParams[this.queryParam] = q;
14569 var options = {params : this.getParams(q)};
14572 options.add = true;
14573 options.params.start = this.page * this.pageSize;
14576 this.store.load(options);
14579 * this code will make the page width larger, at the beginning, the list not align correctly,
14580 * we should expand the list on onLoad
14581 * so command out it
14586 this.selectedIndex = -1;
14591 this.loadNext = false;
14595 getParams : function(q){
14597 //p[this.queryParam] = q;
14601 p.limit = this.pageSize;
14607 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14609 collapse : function(){
14610 if(!this.isExpanded()){
14616 this.hasFocus = false;
14620 this.cancelBtn.hide();
14621 this.trigger.show();
14624 this.tickableInputEl().dom.value = '';
14625 this.tickableInputEl().blur();
14630 Roo.get(document).un('mousedown', this.collapseIf, this);
14631 Roo.get(document).un('mousewheel', this.collapseIf, this);
14632 if (!this.editable) {
14633 Roo.get(document).un('keydown', this.listKeyPress, this);
14635 this.fireEvent('collapse', this);
14641 collapseIf : function(e){
14642 var in_combo = e.within(this.el);
14643 var in_list = e.within(this.list);
14644 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14646 if (in_combo || in_list || is_list) {
14647 //e.stopPropagation();
14652 this.onTickableFooterButtonClick(e, false, false);
14660 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14662 expand : function(){
14664 if(this.isExpanded() || !this.hasFocus){
14668 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14669 this.list.setWidth(lw);
14675 this.restrictHeight();
14679 this.tickItems = Roo.apply([], this.item);
14682 this.cancelBtn.show();
14683 this.trigger.hide();
14686 this.tickableInputEl().focus();
14691 Roo.get(document).on('mousedown', this.collapseIf, this);
14692 Roo.get(document).on('mousewheel', this.collapseIf, this);
14693 if (!this.editable) {
14694 Roo.get(document).on('keydown', this.listKeyPress, this);
14697 this.fireEvent('expand', this);
14701 // Implements the default empty TriggerField.onTriggerClick function
14702 onTriggerClick : function(e)
14704 Roo.log('trigger click');
14706 if(this.disabled || !this.triggerList){
14711 this.loadNext = false;
14713 if(this.isExpanded()){
14715 if (!this.blockFocus) {
14716 this.inputEl().focus();
14720 this.hasFocus = true;
14721 if(this.triggerAction == 'all') {
14722 this.doQuery(this.allQuery, true);
14724 this.doQuery(this.getRawValue());
14726 if (!this.blockFocus) {
14727 this.inputEl().focus();
14732 onTickableTriggerClick : function(e)
14739 this.loadNext = false;
14740 this.hasFocus = true;
14742 if(this.triggerAction == 'all') {
14743 this.doQuery(this.allQuery, true);
14745 this.doQuery(this.getRawValue());
14749 onSearchFieldClick : function(e)
14751 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14752 this.onTickableFooterButtonClick(e, false, false);
14756 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14761 this.loadNext = false;
14762 this.hasFocus = true;
14764 if(this.triggerAction == 'all') {
14765 this.doQuery(this.allQuery, true);
14767 this.doQuery(this.getRawValue());
14771 listKeyPress : function(e)
14773 //Roo.log('listkeypress');
14774 // scroll to first matching element based on key pres..
14775 if (e.isSpecialKey()) {
14778 var k = String.fromCharCode(e.getKey()).toUpperCase();
14781 var csel = this.view.getSelectedNodes();
14782 var cselitem = false;
14784 var ix = this.view.indexOf(csel[0]);
14785 cselitem = this.store.getAt(ix);
14786 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14792 this.store.each(function(v) {
14794 // start at existing selection.
14795 if (cselitem.id == v.id) {
14801 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14802 match = this.store.indexOf(v);
14808 if (match === false) {
14809 return true; // no more action?
14812 this.view.select(match);
14813 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14814 sn.scrollIntoView(sn.dom.parentNode, false);
14817 onViewScroll : function(e, t){
14819 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){
14823 this.hasQuery = true;
14825 this.loading = this.list.select('.loading', true).first();
14827 if(this.loading === null){
14828 this.list.createChild({
14830 cls: 'loading roo-select2-more-results roo-select2-active',
14831 html: 'Loading more results...'
14834 this.loading = this.list.select('.loading', true).first();
14836 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14838 this.loading.hide();
14841 this.loading.show();
14846 this.loadNext = true;
14848 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14853 addItem : function(o)
14855 var dv = ''; // display value
14857 if (this.displayField) {
14858 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14860 // this is an error condition!!!
14861 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14868 var choice = this.choices.createChild({
14870 cls: 'roo-select2-search-choice',
14879 cls: 'roo-select2-search-choice-close fa fa-times',
14884 }, this.searchField);
14886 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14888 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14896 this.inputEl().dom.value = '';
14901 onRemoveItem : function(e, _self, o)
14903 e.preventDefault();
14905 this.lastItem = Roo.apply([], this.item);
14907 var index = this.item.indexOf(o.data) * 1;
14910 Roo.log('not this item?!');
14914 this.item.splice(index, 1);
14919 this.fireEvent('remove', this, e);
14925 syncValue : function()
14927 if(!this.item.length){
14934 Roo.each(this.item, function(i){
14935 if(_this.valueField){
14936 value.push(i[_this.valueField]);
14943 this.value = value.join(',');
14945 if(this.hiddenField){
14946 this.hiddenField.dom.value = this.value;
14949 this.store.fireEvent("datachanged", this.store);
14954 clearItem : function()
14956 if(!this.multiple){
14962 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14970 if(this.tickable && !Roo.isTouch){
14971 this.view.refresh();
14975 inputEl: function ()
14977 if(Roo.isIOS && this.useNativeIOS){
14978 return this.el.select('select.roo-ios-select', true).first();
14981 if(Roo.isTouch && this.mobileTouchView){
14982 return this.el.select('input.form-control',true).first();
14986 return this.searchField;
14989 return this.el.select('input.form-control',true).first();
14992 onTickableFooterButtonClick : function(e, btn, el)
14994 e.preventDefault();
14996 this.lastItem = Roo.apply([], this.item);
14998 if(btn && btn.name == 'cancel'){
14999 this.tickItems = Roo.apply([], this.item);
15008 Roo.each(this.tickItems, function(o){
15016 validate : function()
15018 if(this.getVisibilityEl().hasClass('hidden')){
15022 var v = this.getRawValue();
15025 v = this.getValue();
15028 if(this.disabled || this.allowBlank || v.length){
15033 this.markInvalid();
15037 tickableInputEl : function()
15039 if(!this.tickable || !this.editable){
15040 return this.inputEl();
15043 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15047 getAutoCreateTouchView : function()
15052 cls: 'form-group' //input-group
15058 type : this.inputType,
15059 cls : 'form-control x-combo-noedit',
15060 autocomplete: 'new-password',
15061 placeholder : this.placeholder || '',
15066 input.name = this.name;
15070 input.cls += ' input-' + this.size;
15073 if (this.disabled) {
15074 input.disabled = true;
15085 inputblock.cls += ' input-group';
15087 inputblock.cn.unshift({
15089 cls : 'input-group-addon input-group-prepend input-group-text',
15094 if(this.removable && !this.multiple){
15095 inputblock.cls += ' roo-removable';
15097 inputblock.cn.push({
15100 cls : 'roo-combo-removable-btn close'
15104 if(this.hasFeedback && !this.allowBlank){
15106 inputblock.cls += ' has-feedback';
15108 inputblock.cn.push({
15110 cls: 'glyphicon form-control-feedback'
15117 inputblock.cls += (this.before) ? '' : ' input-group';
15119 inputblock.cn.push({
15121 cls : 'input-group-addon input-group-append input-group-text',
15127 var ibwrap = inputblock;
15132 cls: 'roo-select2-choices',
15136 cls: 'roo-select2-search-field',
15149 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15154 cls: 'form-hidden-field'
15160 if(!this.multiple && this.showToggleBtn){
15167 if (this.caret != false) {
15170 cls: 'fa fa-' + this.caret
15177 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15182 cls: 'combobox-clear',
15196 combobox.cls += ' roo-select2-container-multi';
15199 var align = this.labelAlign || this.parentLabelAlign();
15201 if (align ==='left' && this.fieldLabel.length) {
15206 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15207 tooltip : 'This field is required'
15211 cls : 'control-label col-form-label',
15212 html : this.fieldLabel
15223 var labelCfg = cfg.cn[1];
15224 var contentCfg = cfg.cn[2];
15227 if(this.indicatorpos == 'right'){
15232 cls : 'control-label col-form-label',
15236 html : this.fieldLabel
15240 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15241 tooltip : 'This field is required'
15254 labelCfg = cfg.cn[0];
15255 contentCfg = cfg.cn[1];
15260 if(this.labelWidth > 12){
15261 labelCfg.style = "width: " + this.labelWidth + 'px';
15264 if(this.labelWidth < 13 && this.labelmd == 0){
15265 this.labelmd = this.labelWidth;
15268 if(this.labellg > 0){
15269 labelCfg.cls += ' col-lg-' + this.labellg;
15270 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15273 if(this.labelmd > 0){
15274 labelCfg.cls += ' col-md-' + this.labelmd;
15275 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15278 if(this.labelsm > 0){
15279 labelCfg.cls += ' col-sm-' + this.labelsm;
15280 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15283 if(this.labelxs > 0){
15284 labelCfg.cls += ' col-xs-' + this.labelxs;
15285 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15289 } else if ( this.fieldLabel.length) {
15293 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15294 tooltip : 'This field is required'
15298 cls : 'control-label',
15299 html : this.fieldLabel
15310 if(this.indicatorpos == 'right'){
15314 cls : 'control-label',
15315 html : this.fieldLabel,
15319 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15320 tooltip : 'This field is required'
15337 var settings = this;
15339 ['xs','sm','md','lg'].map(function(size){
15340 if (settings[size]) {
15341 cfg.cls += ' col-' + size + '-' + settings[size];
15348 initTouchView : function()
15350 this.renderTouchView();
15352 this.touchViewEl.on('scroll', function(){
15353 this.el.dom.scrollTop = 0;
15356 this.originalValue = this.getValue();
15358 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15360 this.inputEl().on("click", this.showTouchView, this);
15361 if (this.triggerEl) {
15362 this.triggerEl.on("click", this.showTouchView, this);
15366 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15367 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15369 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15371 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15372 this.store.on('load', this.onTouchViewLoad, this);
15373 this.store.on('loadexception', this.onTouchViewLoadException, this);
15375 if(this.hiddenName){
15377 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15379 this.hiddenField.dom.value =
15380 this.hiddenValue !== undefined ? this.hiddenValue :
15381 this.value !== undefined ? this.value : '';
15383 this.el.dom.removeAttribute('name');
15384 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15388 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15389 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15392 if(this.removable && !this.multiple){
15393 var close = this.closeTriggerEl();
15395 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15396 close.on('click', this.removeBtnClick, this, close);
15400 * fix the bug in Safari iOS8
15402 this.inputEl().on("focus", function(e){
15403 document.activeElement.blur();
15406 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15413 renderTouchView : function()
15415 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15416 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15418 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15419 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15421 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15422 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15423 this.touchViewBodyEl.setStyle('overflow', 'auto');
15425 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15426 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15428 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15429 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15433 showTouchView : function()
15439 this.touchViewHeaderEl.hide();
15441 if(this.modalTitle.length){
15442 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15443 this.touchViewHeaderEl.show();
15446 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15447 this.touchViewEl.show();
15449 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15451 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15452 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15454 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15456 if(this.modalTitle.length){
15457 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15460 this.touchViewBodyEl.setHeight(bodyHeight);
15464 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15466 this.touchViewEl.addClass('in');
15469 if(this._touchViewMask){
15470 Roo.get(document.body).addClass("x-body-masked");
15471 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15472 this._touchViewMask.setStyle('z-index', 10000);
15473 this._touchViewMask.addClass('show');
15476 this.doTouchViewQuery();
15480 hideTouchView : function()
15482 this.touchViewEl.removeClass('in');
15486 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15488 this.touchViewEl.setStyle('display', 'none');
15491 if(this._touchViewMask){
15492 this._touchViewMask.removeClass('show');
15493 Roo.get(document.body).removeClass("x-body-masked");
15497 setTouchViewValue : function()
15504 Roo.each(this.tickItems, function(o){
15509 this.hideTouchView();
15512 doTouchViewQuery : function()
15521 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15525 if(!this.alwaysQuery || this.mode == 'local'){
15526 this.onTouchViewLoad();
15533 onTouchViewBeforeLoad : function(combo,opts)
15539 onTouchViewLoad : function()
15541 if(this.store.getCount() < 1){
15542 this.onTouchViewEmptyResults();
15546 this.clearTouchView();
15548 var rawValue = this.getRawValue();
15550 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15552 this.tickItems = [];
15554 this.store.data.each(function(d, rowIndex){
15555 var row = this.touchViewListGroup.createChild(template);
15557 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15558 row.addClass(d.data.cls);
15561 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15564 html : d.data[this.displayField]
15567 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15568 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15571 row.removeClass('selected');
15572 if(!this.multiple && this.valueField &&
15573 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15576 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15577 row.addClass('selected');
15580 if(this.multiple && this.valueField &&
15581 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15585 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15586 this.tickItems.push(d.data);
15589 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15593 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15595 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15597 if(this.modalTitle.length){
15598 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15601 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15603 if(this.mobile_restrict_height && listHeight < bodyHeight){
15604 this.touchViewBodyEl.setHeight(listHeight);
15609 if(firstChecked && listHeight > bodyHeight){
15610 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15615 onTouchViewLoadException : function()
15617 this.hideTouchView();
15620 onTouchViewEmptyResults : function()
15622 this.clearTouchView();
15624 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15626 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15630 clearTouchView : function()
15632 this.touchViewListGroup.dom.innerHTML = '';
15635 onTouchViewClick : function(e, el, o)
15637 e.preventDefault();
15640 var rowIndex = o.rowIndex;
15642 var r = this.store.getAt(rowIndex);
15644 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15646 if(!this.multiple){
15647 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15648 c.dom.removeAttribute('checked');
15651 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15653 this.setFromData(r.data);
15655 var close = this.closeTriggerEl();
15661 this.hideTouchView();
15663 this.fireEvent('select', this, r, rowIndex);
15668 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15669 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15670 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15674 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15675 this.addItem(r.data);
15676 this.tickItems.push(r.data);
15680 getAutoCreateNativeIOS : function()
15683 cls: 'form-group' //input-group,
15688 cls : 'roo-ios-select'
15692 combobox.name = this.name;
15695 if (this.disabled) {
15696 combobox.disabled = true;
15699 var settings = this;
15701 ['xs','sm','md','lg'].map(function(size){
15702 if (settings[size]) {
15703 cfg.cls += ' col-' + size + '-' + settings[size];
15713 initIOSView : function()
15715 this.store.on('load', this.onIOSViewLoad, this);
15720 onIOSViewLoad : function()
15722 if(this.store.getCount() < 1){
15726 this.clearIOSView();
15728 if(this.allowBlank) {
15730 var default_text = '-- SELECT --';
15732 if(this.placeholder.length){
15733 default_text = this.placeholder;
15736 if(this.emptyTitle.length){
15737 default_text += ' - ' + this.emptyTitle + ' -';
15740 var opt = this.inputEl().createChild({
15743 html : default_text
15747 o[this.valueField] = 0;
15748 o[this.displayField] = default_text;
15750 this.ios_options.push({
15757 this.store.data.each(function(d, rowIndex){
15761 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15762 html = d.data[this.displayField];
15767 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15768 value = d.data[this.valueField];
15777 if(this.value == d.data[this.valueField]){
15778 option['selected'] = true;
15781 var opt = this.inputEl().createChild(option);
15783 this.ios_options.push({
15790 this.inputEl().on('change', function(){
15791 this.fireEvent('select', this);
15796 clearIOSView: function()
15798 this.inputEl().dom.innerHTML = '';
15800 this.ios_options = [];
15803 setIOSValue: function(v)
15807 if(!this.ios_options){
15811 Roo.each(this.ios_options, function(opts){
15813 opts.el.dom.removeAttribute('selected');
15815 if(opts.data[this.valueField] != v){
15819 opts.el.dom.setAttribute('selected', true);
15825 * @cfg {Boolean} grow
15829 * @cfg {Number} growMin
15833 * @cfg {Number} growMax
15842 Roo.apply(Roo.bootstrap.ComboBox, {
15846 cls: 'modal-header',
15868 cls: 'list-group-item',
15872 cls: 'roo-combobox-list-group-item-value'
15876 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15890 listItemCheckbox : {
15892 cls: 'list-group-item',
15896 cls: 'roo-combobox-list-group-item-value'
15900 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15916 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15921 cls: 'modal-footer',
15929 cls: 'col-xs-6 text-left',
15932 cls: 'btn btn-danger roo-touch-view-cancel',
15938 cls: 'col-xs-6 text-right',
15941 cls: 'btn btn-success roo-touch-view-ok',
15952 Roo.apply(Roo.bootstrap.ComboBox, {
15954 touchViewTemplate : {
15956 cls: 'modal fade roo-combobox-touch-view',
15960 cls: 'modal-dialog',
15961 style : 'position:fixed', // we have to fix position....
15965 cls: 'modal-content',
15967 Roo.bootstrap.ComboBox.header,
15968 Roo.bootstrap.ComboBox.body,
15969 Roo.bootstrap.ComboBox.footer
15978 * Ext JS Library 1.1.1
15979 * Copyright(c) 2006-2007, Ext JS, LLC.
15981 * Originally Released Under LGPL - original licence link has changed is not relivant.
15984 * <script type="text/javascript">
15989 * @extends Roo.util.Observable
15990 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
15991 * This class also supports single and multi selection modes. <br>
15992 * Create a data model bound view:
15994 var store = new Roo.data.Store(...);
15996 var view = new Roo.View({
15998 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16000 singleSelect: true,
16001 selectedClass: "ydataview-selected",
16005 // listen for node click?
16006 view.on("click", function(vw, index, node, e){
16007 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16011 dataModel.load("foobar.xml");
16013 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16015 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16016 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16018 * Note: old style constructor is still suported (container, template, config)
16021 * Create a new View
16022 * @param {Object} config The config object
16025 Roo.View = function(config, depreciated_tpl, depreciated_config){
16027 this.parent = false;
16029 if (typeof(depreciated_tpl) == 'undefined') {
16030 // new way.. - universal constructor.
16031 Roo.apply(this, config);
16032 this.el = Roo.get(this.el);
16035 this.el = Roo.get(config);
16036 this.tpl = depreciated_tpl;
16037 Roo.apply(this, depreciated_config);
16039 this.wrapEl = this.el.wrap().wrap();
16040 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16043 if(typeof(this.tpl) == "string"){
16044 this.tpl = new Roo.Template(this.tpl);
16046 // support xtype ctors..
16047 this.tpl = new Roo.factory(this.tpl, Roo);
16051 this.tpl.compile();
16056 * @event beforeclick
16057 * Fires before a click is processed. Returns false to cancel the default action.
16058 * @param {Roo.View} this
16059 * @param {Number} index The index of the target node
16060 * @param {HTMLElement} node The target node
16061 * @param {Roo.EventObject} e The raw event object
16063 "beforeclick" : true,
16066 * Fires when a template node is clicked.
16067 * @param {Roo.View} this
16068 * @param {Number} index The index of the target node
16069 * @param {HTMLElement} node The target node
16070 * @param {Roo.EventObject} e The raw event object
16075 * Fires when a template node is double clicked.
16076 * @param {Roo.View} this
16077 * @param {Number} index The index of the target node
16078 * @param {HTMLElement} node The target node
16079 * @param {Roo.EventObject} e The raw event object
16083 * @event contextmenu
16084 * Fires when a template node is right clicked.
16085 * @param {Roo.View} this
16086 * @param {Number} index The index of the target node
16087 * @param {HTMLElement} node The target node
16088 * @param {Roo.EventObject} e The raw event object
16090 "contextmenu" : true,
16092 * @event selectionchange
16093 * Fires when the selected nodes change.
16094 * @param {Roo.View} this
16095 * @param {Array} selections Array of the selected nodes
16097 "selectionchange" : true,
16100 * @event beforeselect
16101 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16102 * @param {Roo.View} this
16103 * @param {HTMLElement} node The node to be selected
16104 * @param {Array} selections Array of currently selected nodes
16106 "beforeselect" : true,
16108 * @event preparedata
16109 * Fires on every row to render, to allow you to change the data.
16110 * @param {Roo.View} this
16111 * @param {Object} data to be rendered (change this)
16113 "preparedata" : true
16121 "click": this.onClick,
16122 "dblclick": this.onDblClick,
16123 "contextmenu": this.onContextMenu,
16127 this.selections = [];
16129 this.cmp = new Roo.CompositeElementLite([]);
16131 this.store = Roo.factory(this.store, Roo.data);
16132 this.setStore(this.store, true);
16135 if ( this.footer && this.footer.xtype) {
16137 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16139 this.footer.dataSource = this.store;
16140 this.footer.container = fctr;
16141 this.footer = Roo.factory(this.footer, Roo);
16142 fctr.insertFirst(this.el);
16144 // this is a bit insane - as the paging toolbar seems to detach the el..
16145 // dom.parentNode.parentNode.parentNode
16146 // they get detached?
16150 Roo.View.superclass.constructor.call(this);
16155 Roo.extend(Roo.View, Roo.util.Observable, {
16158 * @cfg {Roo.data.Store} store Data store to load data from.
16163 * @cfg {String|Roo.Element} el The container element.
16168 * @cfg {String|Roo.Template} tpl The template used by this View
16172 * @cfg {String} dataName the named area of the template to use as the data area
16173 * Works with domtemplates roo-name="name"
16177 * @cfg {String} selectedClass The css class to add to selected nodes
16179 selectedClass : "x-view-selected",
16181 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16186 * @cfg {String} text to display on mask (default Loading)
16190 * @cfg {Boolean} multiSelect Allow multiple selection
16192 multiSelect : false,
16194 * @cfg {Boolean} singleSelect Allow single selection
16196 singleSelect: false,
16199 * @cfg {Boolean} toggleSelect - selecting
16201 toggleSelect : false,
16204 * @cfg {Boolean} tickable - selecting
16209 * Returns the element this view is bound to.
16210 * @return {Roo.Element}
16212 getEl : function(){
16213 return this.wrapEl;
16219 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16221 refresh : function(){
16222 //Roo.log('refresh');
16225 // if we are using something like 'domtemplate', then
16226 // the what gets used is:
16227 // t.applySubtemplate(NAME, data, wrapping data..)
16228 // the outer template then get' applied with
16229 // the store 'extra data'
16230 // and the body get's added to the
16231 // roo-name="data" node?
16232 // <span class='roo-tpl-{name}'></span> ?????
16236 this.clearSelections();
16237 this.el.update("");
16239 var records = this.store.getRange();
16240 if(records.length < 1) {
16242 // is this valid?? = should it render a template??
16244 this.el.update(this.emptyText);
16248 if (this.dataName) {
16249 this.el.update(t.apply(this.store.meta)); //????
16250 el = this.el.child('.roo-tpl-' + this.dataName);
16253 for(var i = 0, len = records.length; i < len; i++){
16254 var data = this.prepareData(records[i].data, i, records[i]);
16255 this.fireEvent("preparedata", this, data, i, records[i]);
16257 var d = Roo.apply({}, data);
16260 Roo.apply(d, {'roo-id' : Roo.id()});
16264 Roo.each(this.parent.item, function(item){
16265 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16268 Roo.apply(d, {'roo-data-checked' : 'checked'});
16272 html[html.length] = Roo.util.Format.trim(
16274 t.applySubtemplate(this.dataName, d, this.store.meta) :
16281 el.update(html.join(""));
16282 this.nodes = el.dom.childNodes;
16283 this.updateIndexes(0);
16288 * Function to override to reformat the data that is sent to
16289 * the template for each node.
16290 * DEPRICATED - use the preparedata event handler.
16291 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16292 * a JSON object for an UpdateManager bound view).
16294 prepareData : function(data, index, record)
16296 this.fireEvent("preparedata", this, data, index, record);
16300 onUpdate : function(ds, record){
16301 // Roo.log('on update');
16302 this.clearSelections();
16303 var index = this.store.indexOf(record);
16304 var n = this.nodes[index];
16305 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16306 n.parentNode.removeChild(n);
16307 this.updateIndexes(index, index);
16313 onAdd : function(ds, records, index)
16315 //Roo.log(['on Add', ds, records, index] );
16316 this.clearSelections();
16317 if(this.nodes.length == 0){
16321 var n = this.nodes[index];
16322 for(var i = 0, len = records.length; i < len; i++){
16323 var d = this.prepareData(records[i].data, i, records[i]);
16325 this.tpl.insertBefore(n, d);
16328 this.tpl.append(this.el, d);
16331 this.updateIndexes(index);
16334 onRemove : function(ds, record, index){
16335 // Roo.log('onRemove');
16336 this.clearSelections();
16337 var el = this.dataName ?
16338 this.el.child('.roo-tpl-' + this.dataName) :
16341 el.dom.removeChild(this.nodes[index]);
16342 this.updateIndexes(index);
16346 * Refresh an individual node.
16347 * @param {Number} index
16349 refreshNode : function(index){
16350 this.onUpdate(this.store, this.store.getAt(index));
16353 updateIndexes : function(startIndex, endIndex){
16354 var ns = this.nodes;
16355 startIndex = startIndex || 0;
16356 endIndex = endIndex || ns.length - 1;
16357 for(var i = startIndex; i <= endIndex; i++){
16358 ns[i].nodeIndex = i;
16363 * Changes the data store this view uses and refresh the view.
16364 * @param {Store} store
16366 setStore : function(store, initial){
16367 if(!initial && this.store){
16368 this.store.un("datachanged", this.refresh);
16369 this.store.un("add", this.onAdd);
16370 this.store.un("remove", this.onRemove);
16371 this.store.un("update", this.onUpdate);
16372 this.store.un("clear", this.refresh);
16373 this.store.un("beforeload", this.onBeforeLoad);
16374 this.store.un("load", this.onLoad);
16375 this.store.un("loadexception", this.onLoad);
16379 store.on("datachanged", this.refresh, this);
16380 store.on("add", this.onAdd, this);
16381 store.on("remove", this.onRemove, this);
16382 store.on("update", this.onUpdate, this);
16383 store.on("clear", this.refresh, this);
16384 store.on("beforeload", this.onBeforeLoad, this);
16385 store.on("load", this.onLoad, this);
16386 store.on("loadexception", this.onLoad, this);
16394 * onbeforeLoad - masks the loading area.
16397 onBeforeLoad : function(store,opts)
16399 //Roo.log('onBeforeLoad');
16401 this.el.update("");
16403 this.el.mask(this.mask ? this.mask : "Loading" );
16405 onLoad : function ()
16412 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16413 * @param {HTMLElement} node
16414 * @return {HTMLElement} The template node
16416 findItemFromChild : function(node){
16417 var el = this.dataName ?
16418 this.el.child('.roo-tpl-' + this.dataName,true) :
16421 if(!node || node.parentNode == el){
16424 var p = node.parentNode;
16425 while(p && p != el){
16426 if(p.parentNode == el){
16435 onClick : function(e){
16436 var item = this.findItemFromChild(e.getTarget());
16438 var index = this.indexOf(item);
16439 if(this.onItemClick(item, index, e) !== false){
16440 this.fireEvent("click", this, index, item, e);
16443 this.clearSelections();
16448 onContextMenu : function(e){
16449 var item = this.findItemFromChild(e.getTarget());
16451 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16456 onDblClick : function(e){
16457 var item = this.findItemFromChild(e.getTarget());
16459 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16463 onItemClick : function(item, index, e)
16465 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16468 if (this.toggleSelect) {
16469 var m = this.isSelected(item) ? 'unselect' : 'select';
16472 _t[m](item, true, false);
16475 if(this.multiSelect || this.singleSelect){
16476 if(this.multiSelect && e.shiftKey && this.lastSelection){
16477 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16479 this.select(item, this.multiSelect && e.ctrlKey);
16480 this.lastSelection = item;
16483 if(!this.tickable){
16484 e.preventDefault();
16492 * Get the number of selected nodes.
16495 getSelectionCount : function(){
16496 return this.selections.length;
16500 * Get the currently selected nodes.
16501 * @return {Array} An array of HTMLElements
16503 getSelectedNodes : function(){
16504 return this.selections;
16508 * Get the indexes of the selected nodes.
16511 getSelectedIndexes : function(){
16512 var indexes = [], s = this.selections;
16513 for(var i = 0, len = s.length; i < len; i++){
16514 indexes.push(s[i].nodeIndex);
16520 * Clear all selections
16521 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16523 clearSelections : function(suppressEvent){
16524 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16525 this.cmp.elements = this.selections;
16526 this.cmp.removeClass(this.selectedClass);
16527 this.selections = [];
16528 if(!suppressEvent){
16529 this.fireEvent("selectionchange", this, this.selections);
16535 * Returns true if the passed node is selected
16536 * @param {HTMLElement/Number} node The node or node index
16537 * @return {Boolean}
16539 isSelected : function(node){
16540 var s = this.selections;
16544 node = this.getNode(node);
16545 return s.indexOf(node) !== -1;
16550 * @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
16551 * @param {Boolean} keepExisting (optional) true to keep existing selections
16552 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16554 select : function(nodeInfo, keepExisting, suppressEvent){
16555 if(nodeInfo instanceof Array){
16557 this.clearSelections(true);
16559 for(var i = 0, len = nodeInfo.length; i < len; i++){
16560 this.select(nodeInfo[i], true, true);
16564 var node = this.getNode(nodeInfo);
16565 if(!node || this.isSelected(node)){
16566 return; // already selected.
16569 this.clearSelections(true);
16572 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16573 Roo.fly(node).addClass(this.selectedClass);
16574 this.selections.push(node);
16575 if(!suppressEvent){
16576 this.fireEvent("selectionchange", this, this.selections);
16584 * @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
16585 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16586 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16588 unselect : function(nodeInfo, keepExisting, suppressEvent)
16590 if(nodeInfo instanceof Array){
16591 Roo.each(this.selections, function(s) {
16592 this.unselect(s, nodeInfo);
16596 var node = this.getNode(nodeInfo);
16597 if(!node || !this.isSelected(node)){
16598 //Roo.log("not selected");
16599 return; // not selected.
16603 Roo.each(this.selections, function(s) {
16605 Roo.fly(node).removeClass(this.selectedClass);
16612 this.selections= ns;
16613 this.fireEvent("selectionchange", this, this.selections);
16617 * Gets a template node.
16618 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16619 * @return {HTMLElement} The node or null if it wasn't found
16621 getNode : function(nodeInfo){
16622 if(typeof nodeInfo == "string"){
16623 return document.getElementById(nodeInfo);
16624 }else if(typeof nodeInfo == "number"){
16625 return this.nodes[nodeInfo];
16631 * Gets a range template nodes.
16632 * @param {Number} startIndex
16633 * @param {Number} endIndex
16634 * @return {Array} An array of nodes
16636 getNodes : function(start, end){
16637 var ns = this.nodes;
16638 start = start || 0;
16639 end = typeof end == "undefined" ? ns.length - 1 : end;
16642 for(var i = start; i <= end; i++){
16646 for(var i = start; i >= end; i--){
16654 * Finds the index of the passed node
16655 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16656 * @return {Number} The index of the node or -1
16658 indexOf : function(node){
16659 node = this.getNode(node);
16660 if(typeof node.nodeIndex == "number"){
16661 return node.nodeIndex;
16663 var ns = this.nodes;
16664 for(var i = 0, len = ns.length; i < len; i++){
16675 * based on jquery fullcalendar
16679 Roo.bootstrap = Roo.bootstrap || {};
16681 * @class Roo.bootstrap.Calendar
16682 * @extends Roo.bootstrap.Component
16683 * Bootstrap Calendar class
16684 * @cfg {Boolean} loadMask (true|false) default false
16685 * @cfg {Object} header generate the user specific header of the calendar, default false
16688 * Create a new Container
16689 * @param {Object} config The config object
16694 Roo.bootstrap.Calendar = function(config){
16695 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16699 * Fires when a date is selected
16700 * @param {DatePicker} this
16701 * @param {Date} date The selected date
16705 * @event monthchange
16706 * Fires when the displayed month changes
16707 * @param {DatePicker} this
16708 * @param {Date} date The selected month
16710 'monthchange': true,
16712 * @event evententer
16713 * Fires when mouse over an event
16714 * @param {Calendar} this
16715 * @param {event} Event
16717 'evententer': true,
16719 * @event eventleave
16720 * Fires when the mouse leaves an
16721 * @param {Calendar} this
16724 'eventleave': true,
16726 * @event eventclick
16727 * Fires when the mouse click an
16728 * @param {Calendar} this
16737 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16740 * @cfg {Number} startDay
16741 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16749 getAutoCreate : function(){
16752 var fc_button = function(name, corner, style, content ) {
16753 return Roo.apply({},{
16755 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16757 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16760 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16771 style : 'width:100%',
16778 cls : 'fc-header-left',
16780 fc_button('prev', 'left', 'arrow', '‹' ),
16781 fc_button('next', 'right', 'arrow', '›' ),
16782 { tag: 'span', cls: 'fc-header-space' },
16783 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16791 cls : 'fc-header-center',
16795 cls: 'fc-header-title',
16798 html : 'month / year'
16806 cls : 'fc-header-right',
16808 /* fc_button('month', 'left', '', 'month' ),
16809 fc_button('week', '', '', 'week' ),
16810 fc_button('day', 'right', '', 'day' )
16822 header = this.header;
16825 var cal_heads = function() {
16827 // fixme - handle this.
16829 for (var i =0; i < Date.dayNames.length; i++) {
16830 var d = Date.dayNames[i];
16833 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16834 html : d.substring(0,3)
16838 ret[0].cls += ' fc-first';
16839 ret[6].cls += ' fc-last';
16842 var cal_cell = function(n) {
16845 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16850 cls: 'fc-day-number',
16854 cls: 'fc-day-content',
16858 style: 'position: relative;' // height: 17px;
16870 var cal_rows = function() {
16873 for (var r = 0; r < 6; r++) {
16880 for (var i =0; i < Date.dayNames.length; i++) {
16881 var d = Date.dayNames[i];
16882 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16885 row.cn[0].cls+=' fc-first';
16886 row.cn[0].cn[0].style = 'min-height:90px';
16887 row.cn[6].cls+=' fc-last';
16891 ret[0].cls += ' fc-first';
16892 ret[4].cls += ' fc-prev-last';
16893 ret[5].cls += ' fc-last';
16900 cls: 'fc-border-separate',
16901 style : 'width:100%',
16909 cls : 'fc-first fc-last',
16927 cls : 'fc-content',
16928 style : "position: relative;",
16931 cls : 'fc-view fc-view-month fc-grid',
16932 style : 'position: relative',
16933 unselectable : 'on',
16936 cls : 'fc-event-container',
16937 style : 'position:absolute;z-index:8;top:0;left:0;'
16955 initEvents : function()
16958 throw "can not find store for calendar";
16964 style: "text-align:center",
16968 style: "background-color:white;width:50%;margin:250 auto",
16972 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16983 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16985 var size = this.el.select('.fc-content', true).first().getSize();
16986 this.maskEl.setSize(size.width, size.height);
16987 this.maskEl.enableDisplayMode("block");
16988 if(!this.loadMask){
16989 this.maskEl.hide();
16992 this.store = Roo.factory(this.store, Roo.data);
16993 this.store.on('load', this.onLoad, this);
16994 this.store.on('beforeload', this.onBeforeLoad, this);
16998 this.cells = this.el.select('.fc-day',true);
16999 //Roo.log(this.cells);
17000 this.textNodes = this.el.query('.fc-day-number');
17001 this.cells.addClassOnOver('fc-state-hover');
17003 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17004 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17005 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17006 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17008 this.on('monthchange', this.onMonthChange, this);
17010 this.update(new Date().clearTime());
17013 resize : function() {
17014 var sz = this.el.getSize();
17016 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17017 this.el.select('.fc-day-content div',true).setHeight(34);
17022 showPrevMonth : function(e){
17023 this.update(this.activeDate.add("mo", -1));
17025 showToday : function(e){
17026 this.update(new Date().clearTime());
17029 showNextMonth : function(e){
17030 this.update(this.activeDate.add("mo", 1));
17034 showPrevYear : function(){
17035 this.update(this.activeDate.add("y", -1));
17039 showNextYear : function(){
17040 this.update(this.activeDate.add("y", 1));
17045 update : function(date)
17047 var vd = this.activeDate;
17048 this.activeDate = date;
17049 // if(vd && this.el){
17050 // var t = date.getTime();
17051 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17052 // Roo.log('using add remove');
17054 // this.fireEvent('monthchange', this, date);
17056 // this.cells.removeClass("fc-state-highlight");
17057 // this.cells.each(function(c){
17058 // if(c.dateValue == t){
17059 // c.addClass("fc-state-highlight");
17060 // setTimeout(function(){
17061 // try{c.dom.firstChild.focus();}catch(e){}
17071 var days = date.getDaysInMonth();
17073 var firstOfMonth = date.getFirstDateOfMonth();
17074 var startingPos = firstOfMonth.getDay()-this.startDay;
17076 if(startingPos < this.startDay){
17080 var pm = date.add(Date.MONTH, -1);
17081 var prevStart = pm.getDaysInMonth()-startingPos;
17083 this.cells = this.el.select('.fc-day',true);
17084 this.textNodes = this.el.query('.fc-day-number');
17085 this.cells.addClassOnOver('fc-state-hover');
17087 var cells = this.cells.elements;
17088 var textEls = this.textNodes;
17090 Roo.each(cells, function(cell){
17091 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17094 days += startingPos;
17096 // convert everything to numbers so it's fast
17097 var day = 86400000;
17098 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17101 //Roo.log(prevStart);
17103 var today = new Date().clearTime().getTime();
17104 var sel = date.clearTime().getTime();
17105 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17106 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17107 var ddMatch = this.disabledDatesRE;
17108 var ddText = this.disabledDatesText;
17109 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17110 var ddaysText = this.disabledDaysText;
17111 var format = this.format;
17113 var setCellClass = function(cal, cell){
17117 //Roo.log('set Cell Class');
17119 var t = d.getTime();
17123 cell.dateValue = t;
17125 cell.className += " fc-today";
17126 cell.className += " fc-state-highlight";
17127 cell.title = cal.todayText;
17130 // disable highlight in other month..
17131 //cell.className += " fc-state-highlight";
17136 cell.className = " fc-state-disabled";
17137 cell.title = cal.minText;
17141 cell.className = " fc-state-disabled";
17142 cell.title = cal.maxText;
17146 if(ddays.indexOf(d.getDay()) != -1){
17147 cell.title = ddaysText;
17148 cell.className = " fc-state-disabled";
17151 if(ddMatch && format){
17152 var fvalue = d.dateFormat(format);
17153 if(ddMatch.test(fvalue)){
17154 cell.title = ddText.replace("%0", fvalue);
17155 cell.className = " fc-state-disabled";
17159 if (!cell.initialClassName) {
17160 cell.initialClassName = cell.dom.className;
17163 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17168 for(; i < startingPos; i++) {
17169 textEls[i].innerHTML = (++prevStart);
17170 d.setDate(d.getDate()+1);
17172 cells[i].className = "fc-past fc-other-month";
17173 setCellClass(this, cells[i]);
17178 for(; i < days; i++){
17179 intDay = i - startingPos + 1;
17180 textEls[i].innerHTML = (intDay);
17181 d.setDate(d.getDate()+1);
17183 cells[i].className = ''; // "x-date-active";
17184 setCellClass(this, cells[i]);
17188 for(; i < 42; i++) {
17189 textEls[i].innerHTML = (++extraDays);
17190 d.setDate(d.getDate()+1);
17192 cells[i].className = "fc-future fc-other-month";
17193 setCellClass(this, cells[i]);
17196 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17198 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17200 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17201 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17203 if(totalRows != 6){
17204 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17205 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17208 this.fireEvent('monthchange', this, date);
17212 if(!this.internalRender){
17213 var main = this.el.dom.firstChild;
17214 var w = main.offsetWidth;
17215 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17216 Roo.fly(main).setWidth(w);
17217 this.internalRender = true;
17218 // opera does not respect the auto grow header center column
17219 // then, after it gets a width opera refuses to recalculate
17220 // without a second pass
17221 if(Roo.isOpera && !this.secondPass){
17222 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17223 this.secondPass = true;
17224 this.update.defer(10, this, [date]);
17231 findCell : function(dt) {
17232 dt = dt.clearTime().getTime();
17234 this.cells.each(function(c){
17235 //Roo.log("check " +c.dateValue + '?=' + dt);
17236 if(c.dateValue == dt){
17246 findCells : function(ev) {
17247 var s = ev.start.clone().clearTime().getTime();
17249 var e= ev.end.clone().clearTime().getTime();
17252 this.cells.each(function(c){
17253 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17255 if(c.dateValue > e){
17258 if(c.dateValue < s){
17267 // findBestRow: function(cells)
17271 // for (var i =0 ; i < cells.length;i++) {
17272 // ret = Math.max(cells[i].rows || 0,ret);
17279 addItem : function(ev)
17281 // look for vertical location slot in
17282 var cells = this.findCells(ev);
17284 // ev.row = this.findBestRow(cells);
17286 // work out the location.
17290 for(var i =0; i < cells.length; i++) {
17292 cells[i].row = cells[0].row;
17295 cells[i].row = cells[i].row + 1;
17305 if (crow.start.getY() == cells[i].getY()) {
17307 crow.end = cells[i];
17324 cells[0].events.push(ev);
17326 this.calevents.push(ev);
17329 clearEvents: function() {
17331 if(!this.calevents){
17335 Roo.each(this.cells.elements, function(c){
17341 Roo.each(this.calevents, function(e) {
17342 Roo.each(e.els, function(el) {
17343 el.un('mouseenter' ,this.onEventEnter, this);
17344 el.un('mouseleave' ,this.onEventLeave, this);
17349 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17355 renderEvents: function()
17359 this.cells.each(function(c) {
17368 if(c.row != c.events.length){
17369 r = 4 - (4 - (c.row - c.events.length));
17372 c.events = ev.slice(0, r);
17373 c.more = ev.slice(r);
17375 if(c.more.length && c.more.length == 1){
17376 c.events.push(c.more.pop());
17379 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17383 this.cells.each(function(c) {
17385 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17388 for (var e = 0; e < c.events.length; e++){
17389 var ev = c.events[e];
17390 var rows = ev.rows;
17392 for(var i = 0; i < rows.length; i++) {
17394 // how many rows should it span..
17397 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17398 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17400 unselectable : "on",
17403 cls: 'fc-event-inner',
17407 // cls: 'fc-event-time',
17408 // html : cells.length > 1 ? '' : ev.time
17412 cls: 'fc-event-title',
17413 html : String.format('{0}', ev.title)
17420 cls: 'ui-resizable-handle ui-resizable-e',
17421 html : '  '
17428 cfg.cls += ' fc-event-start';
17430 if ((i+1) == rows.length) {
17431 cfg.cls += ' fc-event-end';
17434 var ctr = _this.el.select('.fc-event-container',true).first();
17435 var cg = ctr.createChild(cfg);
17437 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17438 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17440 var r = (c.more.length) ? 1 : 0;
17441 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17442 cg.setWidth(ebox.right - sbox.x -2);
17444 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17445 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17446 cg.on('click', _this.onEventClick, _this, ev);
17457 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17458 style : 'position: absolute',
17459 unselectable : "on",
17462 cls: 'fc-event-inner',
17466 cls: 'fc-event-title',
17474 cls: 'ui-resizable-handle ui-resizable-e',
17475 html : '  '
17481 var ctr = _this.el.select('.fc-event-container',true).first();
17482 var cg = ctr.createChild(cfg);
17484 var sbox = c.select('.fc-day-content',true).first().getBox();
17485 var ebox = c.select('.fc-day-content',true).first().getBox();
17487 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17488 cg.setWidth(ebox.right - sbox.x -2);
17490 cg.on('click', _this.onMoreEventClick, _this, c.more);
17500 onEventEnter: function (e, el,event,d) {
17501 this.fireEvent('evententer', this, el, event);
17504 onEventLeave: function (e, el,event,d) {
17505 this.fireEvent('eventleave', this, el, event);
17508 onEventClick: function (e, el,event,d) {
17509 this.fireEvent('eventclick', this, el, event);
17512 onMonthChange: function () {
17516 onMoreEventClick: function(e, el, more)
17520 this.calpopover.placement = 'right';
17521 this.calpopover.setTitle('More');
17523 this.calpopover.setContent('');
17525 var ctr = this.calpopover.el.select('.popover-content', true).first();
17527 Roo.each(more, function(m){
17529 cls : 'fc-event-hori fc-event-draggable',
17532 var cg = ctr.createChild(cfg);
17534 cg.on('click', _this.onEventClick, _this, m);
17537 this.calpopover.show(el);
17542 onLoad: function ()
17544 this.calevents = [];
17547 if(this.store.getCount() > 0){
17548 this.store.data.each(function(d){
17551 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17552 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17553 time : d.data.start_time,
17554 title : d.data.title,
17555 description : d.data.description,
17556 venue : d.data.venue
17561 this.renderEvents();
17563 if(this.calevents.length && this.loadMask){
17564 this.maskEl.hide();
17568 onBeforeLoad: function()
17570 this.clearEvents();
17572 this.maskEl.show();
17586 * @class Roo.bootstrap.Popover
17587 * @extends Roo.bootstrap.Component
17588 * Bootstrap Popover class
17589 * @cfg {String} html contents of the popover (or false to use children..)
17590 * @cfg {String} title of popover (or false to hide)
17591 * @cfg {String} placement how it is placed
17592 * @cfg {String} trigger click || hover (or false to trigger manually)
17593 * @cfg {String} over what (parent or false to trigger manually.)
17594 * @cfg {Number} delay - delay before showing
17597 * Create a new Popover
17598 * @param {Object} config The config object
17601 Roo.bootstrap.Popover = function(config){
17602 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17608 * After the popover show
17610 * @param {Roo.bootstrap.Popover} this
17615 * After the popover hide
17617 * @param {Roo.bootstrap.Popover} this
17623 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17625 title: 'Fill in a title',
17628 placement : 'right',
17629 trigger : 'hover', // hover
17635 can_build_overlaid : false,
17637 getChildContainer : function()
17639 return this.el.select('.popover-content',true).first();
17642 getAutoCreate : function(){
17645 cls : 'popover roo-dynamic',
17646 style: 'display:block',
17652 cls : 'popover-inner',
17656 cls: 'popover-title popover-header',
17660 cls : 'popover-content popover-body',
17671 setTitle: function(str)
17674 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17676 setContent: function(str)
17679 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17681 // as it get's added to the bottom of the page.
17682 onRender : function(ct, position)
17684 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17686 var cfg = Roo.apply({}, this.getAutoCreate());
17690 cfg.cls += ' ' + this.cls;
17693 cfg.style = this.style;
17695 //Roo.log("adding to ");
17696 this.el = Roo.get(document.body).createChild(cfg, position);
17697 // Roo.log(this.el);
17702 initEvents : function()
17704 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17705 this.el.enableDisplayMode('block');
17707 if (this.over === false) {
17710 if (this.triggers === false) {
17713 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17714 var triggers = this.trigger ? this.trigger.split(' ') : [];
17715 Roo.each(triggers, function(trigger) {
17717 if (trigger == 'click') {
17718 on_el.on('click', this.toggle, this);
17719 } else if (trigger != 'manual') {
17720 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17721 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17723 on_el.on(eventIn ,this.enter, this);
17724 on_el.on(eventOut, this.leave, this);
17735 toggle : function () {
17736 this.hoverState == 'in' ? this.leave() : this.enter();
17739 enter : function () {
17741 clearTimeout(this.timeout);
17743 this.hoverState = 'in';
17745 if (!this.delay || !this.delay.show) {
17750 this.timeout = setTimeout(function () {
17751 if (_t.hoverState == 'in') {
17754 }, this.delay.show)
17757 leave : function() {
17758 clearTimeout(this.timeout);
17760 this.hoverState = 'out';
17762 if (!this.delay || !this.delay.hide) {
17767 this.timeout = setTimeout(function () {
17768 if (_t.hoverState == 'out') {
17771 }, this.delay.hide)
17774 show : function (on_el)
17777 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17781 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17782 if (this.html !== false) {
17783 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17785 this.el.removeClass([
17786 'fade','top','bottom', 'left', 'right','in',
17787 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17789 if (!this.title.length) {
17790 this.el.select('.popover-title',true).hide();
17793 var placement = typeof this.placement == 'function' ?
17794 this.placement.call(this, this.el, on_el) :
17797 var autoToken = /\s?auto?\s?/i;
17798 var autoPlace = autoToken.test(placement);
17800 placement = placement.replace(autoToken, '') || 'top';
17804 //this.el.setXY([0,0]);
17806 this.el.dom.style.display='block';
17807 this.el.addClass(placement);
17809 //this.el.appendTo(on_el);
17811 var p = this.getPosition();
17812 var box = this.el.getBox();
17817 var align = Roo.bootstrap.Popover.alignment[placement];
17820 this.el.alignTo(on_el, align[0],align[1]);
17821 //var arrow = this.el.select('.arrow',true).first();
17822 //arrow.set(align[2],
17824 this.el.addClass('in');
17827 if (this.el.hasClass('fade')) {
17831 this.hoverState = 'in';
17833 this.fireEvent('show', this);
17838 this.el.setXY([0,0]);
17839 this.el.removeClass('in');
17841 this.hoverState = null;
17843 this.fireEvent('hide', this);
17848 Roo.bootstrap.Popover.alignment = {
17849 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17850 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17851 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17852 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17863 * @class Roo.bootstrap.Progress
17864 * @extends Roo.bootstrap.Component
17865 * Bootstrap Progress class
17866 * @cfg {Boolean} striped striped of the progress bar
17867 * @cfg {Boolean} active animated of the progress bar
17871 * Create a new Progress
17872 * @param {Object} config The config object
17875 Roo.bootstrap.Progress = function(config){
17876 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17879 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17884 getAutoCreate : function(){
17892 cfg.cls += ' progress-striped';
17896 cfg.cls += ' active';
17915 * @class Roo.bootstrap.ProgressBar
17916 * @extends Roo.bootstrap.Component
17917 * Bootstrap ProgressBar class
17918 * @cfg {Number} aria_valuenow aria-value now
17919 * @cfg {Number} aria_valuemin aria-value min
17920 * @cfg {Number} aria_valuemax aria-value max
17921 * @cfg {String} label label for the progress bar
17922 * @cfg {String} panel (success | info | warning | danger )
17923 * @cfg {String} role role of the progress bar
17924 * @cfg {String} sr_only text
17928 * Create a new ProgressBar
17929 * @param {Object} config The config object
17932 Roo.bootstrap.ProgressBar = function(config){
17933 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17936 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17940 aria_valuemax : 100,
17946 getAutoCreate : function()
17951 cls: 'progress-bar',
17952 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17964 cfg.role = this.role;
17967 if(this.aria_valuenow){
17968 cfg['aria-valuenow'] = this.aria_valuenow;
17971 if(this.aria_valuemin){
17972 cfg['aria-valuemin'] = this.aria_valuemin;
17975 if(this.aria_valuemax){
17976 cfg['aria-valuemax'] = this.aria_valuemax;
17979 if(this.label && !this.sr_only){
17980 cfg.html = this.label;
17984 cfg.cls += ' progress-bar-' + this.panel;
17990 update : function(aria_valuenow)
17992 this.aria_valuenow = aria_valuenow;
17994 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18009 * @class Roo.bootstrap.TabGroup
18010 * @extends Roo.bootstrap.Column
18011 * Bootstrap Column class
18012 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18013 * @cfg {Boolean} carousel true to make the group behave like a carousel
18014 * @cfg {Boolean} bullets show bullets for the panels
18015 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18016 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18017 * @cfg {Boolean} showarrow (true|false) show arrow default true
18020 * Create a new TabGroup
18021 * @param {Object} config The config object
18024 Roo.bootstrap.TabGroup = function(config){
18025 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18027 this.navId = Roo.id();
18030 Roo.bootstrap.TabGroup.register(this);
18034 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18037 transition : false,
18042 slideOnTouch : false,
18045 getAutoCreate : function()
18047 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18049 cfg.cls += ' tab-content';
18051 if (this.carousel) {
18052 cfg.cls += ' carousel slide';
18055 cls : 'carousel-inner',
18059 if(this.bullets && !Roo.isTouch){
18062 cls : 'carousel-bullets',
18066 if(this.bullets_cls){
18067 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18074 cfg.cn[0].cn.push(bullets);
18077 if(this.showarrow){
18078 cfg.cn[0].cn.push({
18080 class : 'carousel-arrow',
18084 class : 'carousel-prev',
18088 class : 'fa fa-chevron-left'
18094 class : 'carousel-next',
18098 class : 'fa fa-chevron-right'
18111 initEvents: function()
18113 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18114 // this.el.on("touchstart", this.onTouchStart, this);
18117 if(this.autoslide){
18120 this.slideFn = window.setInterval(function() {
18121 _this.showPanelNext();
18125 if(this.showarrow){
18126 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18127 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18133 // onTouchStart : function(e, el, o)
18135 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18139 // this.showPanelNext();
18143 getChildContainer : function()
18145 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18149 * register a Navigation item
18150 * @param {Roo.bootstrap.NavItem} the navitem to add
18152 register : function(item)
18154 this.tabs.push( item);
18155 item.navId = this.navId; // not really needed..
18160 getActivePanel : function()
18163 Roo.each(this.tabs, function(t) {
18173 getPanelByName : function(n)
18176 Roo.each(this.tabs, function(t) {
18177 if (t.tabId == n) {
18185 indexOfPanel : function(p)
18188 Roo.each(this.tabs, function(t,i) {
18189 if (t.tabId == p.tabId) {
18198 * show a specific panel
18199 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18200 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18202 showPanel : function (pan)
18204 if(this.transition || typeof(pan) == 'undefined'){
18205 Roo.log("waiting for the transitionend");
18209 if (typeof(pan) == 'number') {
18210 pan = this.tabs[pan];
18213 if (typeof(pan) == 'string') {
18214 pan = this.getPanelByName(pan);
18217 var cur = this.getActivePanel();
18220 Roo.log('pan or acitve pan is undefined');
18224 if (pan.tabId == this.getActivePanel().tabId) {
18228 if (false === cur.fireEvent('beforedeactivate')) {
18232 if(this.bullets > 0 && !Roo.isTouch){
18233 this.setActiveBullet(this.indexOfPanel(pan));
18236 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18238 this.transition = true;
18239 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18240 var lr = dir == 'next' ? 'left' : 'right';
18241 pan.el.addClass(dir); // or prev
18242 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18243 cur.el.addClass(lr); // or right
18244 pan.el.addClass(lr);
18247 cur.el.on('transitionend', function() {
18248 Roo.log("trans end?");
18250 pan.el.removeClass([lr,dir]);
18251 pan.setActive(true);
18253 cur.el.removeClass([lr]);
18254 cur.setActive(false);
18256 _this.transition = false;
18258 }, this, { single: true } );
18263 cur.setActive(false);
18264 pan.setActive(true);
18269 showPanelNext : function()
18271 var i = this.indexOfPanel(this.getActivePanel());
18273 if (i >= this.tabs.length - 1 && !this.autoslide) {
18277 if (i >= this.tabs.length - 1 && this.autoslide) {
18281 this.showPanel(this.tabs[i+1]);
18284 showPanelPrev : function()
18286 var i = this.indexOfPanel(this.getActivePanel());
18288 if (i < 1 && !this.autoslide) {
18292 if (i < 1 && this.autoslide) {
18293 i = this.tabs.length;
18296 this.showPanel(this.tabs[i-1]);
18300 addBullet: function()
18302 if(!this.bullets || Roo.isTouch){
18305 var ctr = this.el.select('.carousel-bullets',true).first();
18306 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18307 var bullet = ctr.createChild({
18308 cls : 'bullet bullet-' + i
18309 },ctr.dom.lastChild);
18314 bullet.on('click', (function(e, el, o, ii, t){
18316 e.preventDefault();
18318 this.showPanel(ii);
18320 if(this.autoslide && this.slideFn){
18321 clearInterval(this.slideFn);
18322 this.slideFn = window.setInterval(function() {
18323 _this.showPanelNext();
18327 }).createDelegate(this, [i, bullet], true));
18332 setActiveBullet : function(i)
18338 Roo.each(this.el.select('.bullet', true).elements, function(el){
18339 el.removeClass('selected');
18342 var bullet = this.el.select('.bullet-' + i, true).first();
18348 bullet.addClass('selected');
18359 Roo.apply(Roo.bootstrap.TabGroup, {
18363 * register a Navigation Group
18364 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18366 register : function(navgrp)
18368 this.groups[navgrp.navId] = navgrp;
18372 * fetch a Navigation Group based on the navigation ID
18373 * if one does not exist , it will get created.
18374 * @param {string} the navgroup to add
18375 * @returns {Roo.bootstrap.NavGroup} the navgroup
18377 get: function(navId) {
18378 if (typeof(this.groups[navId]) == 'undefined') {
18379 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18381 return this.groups[navId] ;
18396 * @class Roo.bootstrap.TabPanel
18397 * @extends Roo.bootstrap.Component
18398 * Bootstrap TabPanel class
18399 * @cfg {Boolean} active panel active
18400 * @cfg {String} html panel content
18401 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18402 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18403 * @cfg {String} href click to link..
18407 * Create a new TabPanel
18408 * @param {Object} config The config object
18411 Roo.bootstrap.TabPanel = function(config){
18412 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18416 * Fires when the active status changes
18417 * @param {Roo.bootstrap.TabPanel} this
18418 * @param {Boolean} state the new state
18423 * @event beforedeactivate
18424 * Fires before a tab is de-activated - can be used to do validation on a form.
18425 * @param {Roo.bootstrap.TabPanel} this
18426 * @return {Boolean} false if there is an error
18429 'beforedeactivate': true
18432 this.tabId = this.tabId || Roo.id();
18436 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18444 getAutoCreate : function(){
18447 // item is needed for carousel - not sure if it has any effect otherwise
18448 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18449 html: this.html || ''
18453 cfg.cls += ' active';
18457 cfg.tabId = this.tabId;
18464 initEvents: function()
18466 var p = this.parent();
18468 this.navId = this.navId || p.navId;
18470 if (typeof(this.navId) != 'undefined') {
18471 // not really needed.. but just in case.. parent should be a NavGroup.
18472 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18476 var i = tg.tabs.length - 1;
18478 if(this.active && tg.bullets > 0 && i < tg.bullets){
18479 tg.setActiveBullet(i);
18483 this.el.on('click', this.onClick, this);
18486 this.el.on("touchstart", this.onTouchStart, this);
18487 this.el.on("touchmove", this.onTouchMove, this);
18488 this.el.on("touchend", this.onTouchEnd, this);
18493 onRender : function(ct, position)
18495 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18498 setActive : function(state)
18500 Roo.log("panel - set active " + this.tabId + "=" + state);
18502 this.active = state;
18504 this.el.removeClass('active');
18506 } else if (!this.el.hasClass('active')) {
18507 this.el.addClass('active');
18510 this.fireEvent('changed', this, state);
18513 onClick : function(e)
18515 e.preventDefault();
18517 if(!this.href.length){
18521 window.location.href = this.href;
18530 onTouchStart : function(e)
18532 this.swiping = false;
18534 this.startX = e.browserEvent.touches[0].clientX;
18535 this.startY = e.browserEvent.touches[0].clientY;
18538 onTouchMove : function(e)
18540 this.swiping = true;
18542 this.endX = e.browserEvent.touches[0].clientX;
18543 this.endY = e.browserEvent.touches[0].clientY;
18546 onTouchEnd : function(e)
18553 var tabGroup = this.parent();
18555 if(this.endX > this.startX){ // swiping right
18556 tabGroup.showPanelPrev();
18560 if(this.startX > this.endX){ // swiping left
18561 tabGroup.showPanelNext();
18580 * @class Roo.bootstrap.DateField
18581 * @extends Roo.bootstrap.Input
18582 * Bootstrap DateField class
18583 * @cfg {Number} weekStart default 0
18584 * @cfg {String} viewMode default empty, (months|years)
18585 * @cfg {String} minViewMode default empty, (months|years)
18586 * @cfg {Number} startDate default -Infinity
18587 * @cfg {Number} endDate default Infinity
18588 * @cfg {Boolean} todayHighlight default false
18589 * @cfg {Boolean} todayBtn default false
18590 * @cfg {Boolean} calendarWeeks default false
18591 * @cfg {Object} daysOfWeekDisabled default empty
18592 * @cfg {Boolean} singleMode default false (true | false)
18594 * @cfg {Boolean} keyboardNavigation default true
18595 * @cfg {String} language default en
18598 * Create a new DateField
18599 * @param {Object} config The config object
18602 Roo.bootstrap.DateField = function(config){
18603 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18607 * Fires when this field show.
18608 * @param {Roo.bootstrap.DateField} this
18609 * @param {Mixed} date The date value
18614 * Fires when this field hide.
18615 * @param {Roo.bootstrap.DateField} this
18616 * @param {Mixed} date The date value
18621 * Fires when select a date.
18622 * @param {Roo.bootstrap.DateField} this
18623 * @param {Mixed} date The date value
18627 * @event beforeselect
18628 * Fires when before select a date.
18629 * @param {Roo.bootstrap.DateField} this
18630 * @param {Mixed} date The date value
18632 beforeselect : true
18636 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18639 * @cfg {String} format
18640 * The default date format string which can be overriden for localization support. The format must be
18641 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18645 * @cfg {String} altFormats
18646 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18647 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18649 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18657 todayHighlight : false,
18663 keyboardNavigation: true,
18665 calendarWeeks: false,
18667 startDate: -Infinity,
18671 daysOfWeekDisabled: [],
18675 singleMode : false,
18677 UTCDate: function()
18679 return new Date(Date.UTC.apply(Date, arguments));
18682 UTCToday: function()
18684 var today = new Date();
18685 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18688 getDate: function() {
18689 var d = this.getUTCDate();
18690 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18693 getUTCDate: function() {
18697 setDate: function(d) {
18698 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18701 setUTCDate: function(d) {
18703 this.setValue(this.formatDate(this.date));
18706 onRender: function(ct, position)
18709 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18711 this.language = this.language || 'en';
18712 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18713 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18715 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18716 this.format = this.format || 'm/d/y';
18717 this.isInline = false;
18718 this.isInput = true;
18719 this.component = this.el.select('.add-on', true).first() || false;
18720 this.component = (this.component && this.component.length === 0) ? false : this.component;
18721 this.hasInput = this.component && this.inputEl().length;
18723 if (typeof(this.minViewMode === 'string')) {
18724 switch (this.minViewMode) {
18726 this.minViewMode = 1;
18729 this.minViewMode = 2;
18732 this.minViewMode = 0;
18737 if (typeof(this.viewMode === 'string')) {
18738 switch (this.viewMode) {
18751 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18753 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18755 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18757 this.picker().on('mousedown', this.onMousedown, this);
18758 this.picker().on('click', this.onClick, this);
18760 this.picker().addClass('datepicker-dropdown');
18762 this.startViewMode = this.viewMode;
18764 if(this.singleMode){
18765 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18766 v.setVisibilityMode(Roo.Element.DISPLAY);
18770 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18771 v.setStyle('width', '189px');
18775 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18776 if(!this.calendarWeeks){
18781 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18782 v.attr('colspan', function(i, val){
18783 return parseInt(val) + 1;
18788 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18790 this.setStartDate(this.startDate);
18791 this.setEndDate(this.endDate);
18793 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18800 if(this.isInline) {
18805 picker : function()
18807 return this.pickerEl;
18808 // return this.el.select('.datepicker', true).first();
18811 fillDow: function()
18813 var dowCnt = this.weekStart;
18822 if(this.calendarWeeks){
18830 while (dowCnt < this.weekStart + 7) {
18834 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18838 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18841 fillMonths: function()
18844 var months = this.picker().select('>.datepicker-months td', true).first();
18846 months.dom.innerHTML = '';
18852 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18855 months.createChild(month);
18862 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;
18864 if (this.date < this.startDate) {
18865 this.viewDate = new Date(this.startDate);
18866 } else if (this.date > this.endDate) {
18867 this.viewDate = new Date(this.endDate);
18869 this.viewDate = new Date(this.date);
18877 var d = new Date(this.viewDate),
18878 year = d.getUTCFullYear(),
18879 month = d.getUTCMonth(),
18880 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18881 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18882 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18883 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18884 currentDate = this.date && this.date.valueOf(),
18885 today = this.UTCToday();
18887 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18889 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18891 // this.picker.select('>tfoot th.today').
18892 // .text(dates[this.language].today)
18893 // .toggle(this.todayBtn !== false);
18895 this.updateNavArrows();
18898 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18900 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18902 prevMonth.setUTCDate(day);
18904 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18906 var nextMonth = new Date(prevMonth);
18908 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18910 nextMonth = nextMonth.valueOf();
18912 var fillMonths = false;
18914 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18916 while(prevMonth.valueOf() <= nextMonth) {
18919 if (prevMonth.getUTCDay() === this.weekStart) {
18921 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18929 if(this.calendarWeeks){
18930 // ISO 8601: First week contains first thursday.
18931 // ISO also states week starts on Monday, but we can be more abstract here.
18933 // Start of current week: based on weekstart/current date
18934 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18935 // Thursday of this week
18936 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18937 // First Thursday of year, year from thursday
18938 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18939 // Calendar week: ms between thursdays, div ms per day, div 7 days
18940 calWeek = (th - yth) / 864e5 / 7 + 1;
18942 fillMonths.cn.push({
18950 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18952 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18955 if (this.todayHighlight &&
18956 prevMonth.getUTCFullYear() == today.getFullYear() &&
18957 prevMonth.getUTCMonth() == today.getMonth() &&
18958 prevMonth.getUTCDate() == today.getDate()) {
18959 clsName += ' today';
18962 if (currentDate && prevMonth.valueOf() === currentDate) {
18963 clsName += ' active';
18966 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18967 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18968 clsName += ' disabled';
18971 fillMonths.cn.push({
18973 cls: 'day ' + clsName,
18974 html: prevMonth.getDate()
18977 prevMonth.setDate(prevMonth.getDate()+1);
18980 var currentYear = this.date && this.date.getUTCFullYear();
18981 var currentMonth = this.date && this.date.getUTCMonth();
18983 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18985 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18986 v.removeClass('active');
18988 if(currentYear === year && k === currentMonth){
18989 v.addClass('active');
18992 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18993 v.addClass('disabled');
18999 year = parseInt(year/10, 10) * 10;
19001 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19003 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19006 for (var i = -1; i < 11; i++) {
19007 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19009 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19017 showMode: function(dir)
19020 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19023 Roo.each(this.picker().select('>div',true).elements, function(v){
19024 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19027 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19032 if(this.isInline) {
19036 this.picker().removeClass(['bottom', 'top']);
19038 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19040 * place to the top of element!
19044 this.picker().addClass('top');
19045 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19050 this.picker().addClass('bottom');
19052 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19055 parseDate : function(value)
19057 if(!value || value instanceof Date){
19060 var v = Date.parseDate(value, this.format);
19061 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19062 v = Date.parseDate(value, 'Y-m-d');
19064 if(!v && this.altFormats){
19065 if(!this.altFormatsArray){
19066 this.altFormatsArray = this.altFormats.split("|");
19068 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19069 v = Date.parseDate(value, this.altFormatsArray[i]);
19075 formatDate : function(date, fmt)
19077 return (!date || !(date instanceof Date)) ?
19078 date : date.dateFormat(fmt || this.format);
19081 onFocus : function()
19083 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19087 onBlur : function()
19089 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19091 var d = this.inputEl().getValue();
19098 showPopup : function()
19100 this.picker().show();
19104 this.fireEvent('showpopup', this, this.date);
19107 hidePopup : function()
19109 if(this.isInline) {
19112 this.picker().hide();
19113 this.viewMode = this.startViewMode;
19116 this.fireEvent('hidepopup', this, this.date);
19120 onMousedown: function(e)
19122 e.stopPropagation();
19123 e.preventDefault();
19128 Roo.bootstrap.DateField.superclass.keyup.call(this);
19132 setValue: function(v)
19134 if(this.fireEvent('beforeselect', this, v) !== false){
19135 var d = new Date(this.parseDate(v) ).clearTime();
19137 if(isNaN(d.getTime())){
19138 this.date = this.viewDate = '';
19139 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19143 v = this.formatDate(d);
19145 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19147 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19151 this.fireEvent('select', this, this.date);
19155 getValue: function()
19157 return this.formatDate(this.date);
19160 fireKey: function(e)
19162 if (!this.picker().isVisible()){
19163 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19169 var dateChanged = false,
19171 newDate, newViewDate;
19176 e.preventDefault();
19180 if (!this.keyboardNavigation) {
19183 dir = e.keyCode == 37 ? -1 : 1;
19186 newDate = this.moveYear(this.date, dir);
19187 newViewDate = this.moveYear(this.viewDate, dir);
19188 } else if (e.shiftKey){
19189 newDate = this.moveMonth(this.date, dir);
19190 newViewDate = this.moveMonth(this.viewDate, dir);
19192 newDate = new Date(this.date);
19193 newDate.setUTCDate(this.date.getUTCDate() + dir);
19194 newViewDate = new Date(this.viewDate);
19195 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19197 if (this.dateWithinRange(newDate)){
19198 this.date = newDate;
19199 this.viewDate = newViewDate;
19200 this.setValue(this.formatDate(this.date));
19202 e.preventDefault();
19203 dateChanged = true;
19208 if (!this.keyboardNavigation) {
19211 dir = e.keyCode == 38 ? -1 : 1;
19213 newDate = this.moveYear(this.date, dir);
19214 newViewDate = this.moveYear(this.viewDate, dir);
19215 } else if (e.shiftKey){
19216 newDate = this.moveMonth(this.date, dir);
19217 newViewDate = this.moveMonth(this.viewDate, dir);
19219 newDate = new Date(this.date);
19220 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19221 newViewDate = new Date(this.viewDate);
19222 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19224 if (this.dateWithinRange(newDate)){
19225 this.date = newDate;
19226 this.viewDate = newViewDate;
19227 this.setValue(this.formatDate(this.date));
19229 e.preventDefault();
19230 dateChanged = true;
19234 this.setValue(this.formatDate(this.date));
19236 e.preventDefault();
19239 this.setValue(this.formatDate(this.date));
19253 onClick: function(e)
19255 e.stopPropagation();
19256 e.preventDefault();
19258 var target = e.getTarget();
19260 if(target.nodeName.toLowerCase() === 'i'){
19261 target = Roo.get(target).dom.parentNode;
19264 var nodeName = target.nodeName;
19265 var className = target.className;
19266 var html = target.innerHTML;
19267 //Roo.log(nodeName);
19269 switch(nodeName.toLowerCase()) {
19271 switch(className) {
19277 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19278 switch(this.viewMode){
19280 this.viewDate = this.moveMonth(this.viewDate, dir);
19284 this.viewDate = this.moveYear(this.viewDate, dir);
19290 var date = new Date();
19291 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19293 this.setValue(this.formatDate(this.date));
19300 if (className.indexOf('disabled') < 0) {
19301 this.viewDate.setUTCDate(1);
19302 if (className.indexOf('month') > -1) {
19303 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19305 var year = parseInt(html, 10) || 0;
19306 this.viewDate.setUTCFullYear(year);
19310 if(this.singleMode){
19311 this.setValue(this.formatDate(this.viewDate));
19322 //Roo.log(className);
19323 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19324 var day = parseInt(html, 10) || 1;
19325 var year = this.viewDate.getUTCFullYear(),
19326 month = this.viewDate.getUTCMonth();
19328 if (className.indexOf('old') > -1) {
19335 } else if (className.indexOf('new') > -1) {
19343 //Roo.log([year,month,day]);
19344 this.date = this.UTCDate(year, month, day,0,0,0,0);
19345 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19347 //Roo.log(this.formatDate(this.date));
19348 this.setValue(this.formatDate(this.date));
19355 setStartDate: function(startDate)
19357 this.startDate = startDate || -Infinity;
19358 if (this.startDate !== -Infinity) {
19359 this.startDate = this.parseDate(this.startDate);
19362 this.updateNavArrows();
19365 setEndDate: function(endDate)
19367 this.endDate = endDate || Infinity;
19368 if (this.endDate !== Infinity) {
19369 this.endDate = this.parseDate(this.endDate);
19372 this.updateNavArrows();
19375 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19377 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19378 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19379 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19381 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19382 return parseInt(d, 10);
19385 this.updateNavArrows();
19388 updateNavArrows: function()
19390 if(this.singleMode){
19394 var d = new Date(this.viewDate),
19395 year = d.getUTCFullYear(),
19396 month = d.getUTCMonth();
19398 Roo.each(this.picker().select('.prev', true).elements, function(v){
19400 switch (this.viewMode) {
19403 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19409 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19416 Roo.each(this.picker().select('.next', true).elements, function(v){
19418 switch (this.viewMode) {
19421 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19427 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19435 moveMonth: function(date, dir)
19440 var new_date = new Date(date.valueOf()),
19441 day = new_date.getUTCDate(),
19442 month = new_date.getUTCMonth(),
19443 mag = Math.abs(dir),
19445 dir = dir > 0 ? 1 : -1;
19448 // If going back one month, make sure month is not current month
19449 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19451 return new_date.getUTCMonth() == month;
19453 // If going forward one month, make sure month is as expected
19454 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19456 return new_date.getUTCMonth() != new_month;
19458 new_month = month + dir;
19459 new_date.setUTCMonth(new_month);
19460 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19461 if (new_month < 0 || new_month > 11) {
19462 new_month = (new_month + 12) % 12;
19465 // For magnitudes >1, move one month at a time...
19466 for (var i=0; i<mag; i++) {
19467 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19468 new_date = this.moveMonth(new_date, dir);
19470 // ...then reset the day, keeping it in the new month
19471 new_month = new_date.getUTCMonth();
19472 new_date.setUTCDate(day);
19474 return new_month != new_date.getUTCMonth();
19477 // Common date-resetting loop -- if date is beyond end of month, make it
19480 new_date.setUTCDate(--day);
19481 new_date.setUTCMonth(new_month);
19486 moveYear: function(date, dir)
19488 return this.moveMonth(date, dir*12);
19491 dateWithinRange: function(date)
19493 return date >= this.startDate && date <= this.endDate;
19499 this.picker().remove();
19502 validateValue : function(value)
19504 if(this.getVisibilityEl().hasClass('hidden')){
19508 if(value.length < 1) {
19509 if(this.allowBlank){
19515 if(value.length < this.minLength){
19518 if(value.length > this.maxLength){
19522 var vt = Roo.form.VTypes;
19523 if(!vt[this.vtype](value, this)){
19527 if(typeof this.validator == "function"){
19528 var msg = this.validator(value);
19534 if(this.regex && !this.regex.test(value)){
19538 if(typeof(this.parseDate(value)) == 'undefined'){
19542 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19546 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19556 this.date = this.viewDate = '';
19558 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19563 Roo.apply(Roo.bootstrap.DateField, {
19574 html: '<i class="fa fa-arrow-left"/>'
19584 html: '<i class="fa fa-arrow-right"/>'
19626 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19627 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19628 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19629 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19630 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19643 navFnc: 'FullYear',
19648 navFnc: 'FullYear',
19653 Roo.apply(Roo.bootstrap.DateField, {
19657 cls: 'datepicker dropdown-menu roo-dynamic',
19661 cls: 'datepicker-days',
19665 cls: 'table-condensed',
19667 Roo.bootstrap.DateField.head,
19671 Roo.bootstrap.DateField.footer
19678 cls: 'datepicker-months',
19682 cls: 'table-condensed',
19684 Roo.bootstrap.DateField.head,
19685 Roo.bootstrap.DateField.content,
19686 Roo.bootstrap.DateField.footer
19693 cls: 'datepicker-years',
19697 cls: 'table-condensed',
19699 Roo.bootstrap.DateField.head,
19700 Roo.bootstrap.DateField.content,
19701 Roo.bootstrap.DateField.footer
19720 * @class Roo.bootstrap.TimeField
19721 * @extends Roo.bootstrap.Input
19722 * Bootstrap DateField class
19726 * Create a new TimeField
19727 * @param {Object} config The config object
19730 Roo.bootstrap.TimeField = function(config){
19731 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19735 * Fires when this field show.
19736 * @param {Roo.bootstrap.DateField} thisthis
19737 * @param {Mixed} date The date value
19742 * Fires when this field hide.
19743 * @param {Roo.bootstrap.DateField} this
19744 * @param {Mixed} date The date value
19749 * Fires when select a date.
19750 * @param {Roo.bootstrap.DateField} this
19751 * @param {Mixed} date The date value
19757 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19760 * @cfg {String} format
19761 * The default time format string which can be overriden for localization support. The format must be
19762 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19766 onRender: function(ct, position)
19769 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19771 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19773 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19775 this.pop = this.picker().select('>.datepicker-time',true).first();
19776 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19778 this.picker().on('mousedown', this.onMousedown, this);
19779 this.picker().on('click', this.onClick, this);
19781 this.picker().addClass('datepicker-dropdown');
19786 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19787 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19788 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19789 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19790 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19791 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19795 fireKey: function(e){
19796 if (!this.picker().isVisible()){
19797 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19803 e.preventDefault();
19811 this.onTogglePeriod();
19814 this.onIncrementMinutes();
19817 this.onDecrementMinutes();
19826 onClick: function(e) {
19827 e.stopPropagation();
19828 e.preventDefault();
19831 picker : function()
19833 return this.el.select('.datepicker', true).first();
19836 fillTime: function()
19838 var time = this.pop.select('tbody', true).first();
19840 time.dom.innerHTML = '';
19855 cls: 'hours-up glyphicon glyphicon-chevron-up'
19875 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19896 cls: 'timepicker-hour',
19911 cls: 'timepicker-minute',
19926 cls: 'btn btn-primary period',
19948 cls: 'hours-down glyphicon glyphicon-chevron-down'
19968 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19986 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19993 var hours = this.time.getHours();
19994 var minutes = this.time.getMinutes();
20007 hours = hours - 12;
20011 hours = '0' + hours;
20015 minutes = '0' + minutes;
20018 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20019 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20020 this.pop.select('button', true).first().dom.innerHTML = period;
20026 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20028 var cls = ['bottom'];
20030 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20037 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20042 this.picker().addClass(cls.join('-'));
20046 Roo.each(cls, function(c){
20048 _this.picker().setTop(_this.inputEl().getHeight());
20052 _this.picker().setTop(0 - _this.picker().getHeight());
20057 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20061 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20068 onFocus : function()
20070 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20074 onBlur : function()
20076 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20082 this.picker().show();
20087 this.fireEvent('show', this, this.date);
20092 this.picker().hide();
20095 this.fireEvent('hide', this, this.date);
20098 setTime : function()
20101 this.setValue(this.time.format(this.format));
20103 this.fireEvent('select', this, this.date);
20108 onMousedown: function(e){
20109 e.stopPropagation();
20110 e.preventDefault();
20113 onIncrementHours: function()
20115 Roo.log('onIncrementHours');
20116 this.time = this.time.add(Date.HOUR, 1);
20121 onDecrementHours: function()
20123 Roo.log('onDecrementHours');
20124 this.time = this.time.add(Date.HOUR, -1);
20128 onIncrementMinutes: function()
20130 Roo.log('onIncrementMinutes');
20131 this.time = this.time.add(Date.MINUTE, 1);
20135 onDecrementMinutes: function()
20137 Roo.log('onDecrementMinutes');
20138 this.time = this.time.add(Date.MINUTE, -1);
20142 onTogglePeriod: function()
20144 Roo.log('onTogglePeriod');
20145 this.time = this.time.add(Date.HOUR, 12);
20152 Roo.apply(Roo.bootstrap.TimeField, {
20182 cls: 'btn btn-info ok',
20194 Roo.apply(Roo.bootstrap.TimeField, {
20198 cls: 'datepicker dropdown-menu',
20202 cls: 'datepicker-time',
20206 cls: 'table-condensed',
20208 Roo.bootstrap.TimeField.content,
20209 Roo.bootstrap.TimeField.footer
20228 * @class Roo.bootstrap.MonthField
20229 * @extends Roo.bootstrap.Input
20230 * Bootstrap MonthField class
20232 * @cfg {String} language default en
20235 * Create a new MonthField
20236 * @param {Object} config The config object
20239 Roo.bootstrap.MonthField = function(config){
20240 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20245 * Fires when this field show.
20246 * @param {Roo.bootstrap.MonthField} this
20247 * @param {Mixed} date The date value
20252 * Fires when this field hide.
20253 * @param {Roo.bootstrap.MonthField} this
20254 * @param {Mixed} date The date value
20259 * Fires when select a date.
20260 * @param {Roo.bootstrap.MonthField} this
20261 * @param {String} oldvalue The old value
20262 * @param {String} newvalue The new value
20268 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20270 onRender: function(ct, position)
20273 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20275 this.language = this.language || 'en';
20276 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20277 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20279 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20280 this.isInline = false;
20281 this.isInput = true;
20282 this.component = this.el.select('.add-on', true).first() || false;
20283 this.component = (this.component && this.component.length === 0) ? false : this.component;
20284 this.hasInput = this.component && this.inputEL().length;
20286 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20288 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20290 this.picker().on('mousedown', this.onMousedown, this);
20291 this.picker().on('click', this.onClick, this);
20293 this.picker().addClass('datepicker-dropdown');
20295 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20296 v.setStyle('width', '189px');
20303 if(this.isInline) {
20309 setValue: function(v, suppressEvent)
20311 var o = this.getValue();
20313 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20317 if(suppressEvent !== true){
20318 this.fireEvent('select', this, o, v);
20323 getValue: function()
20328 onClick: function(e)
20330 e.stopPropagation();
20331 e.preventDefault();
20333 var target = e.getTarget();
20335 if(target.nodeName.toLowerCase() === 'i'){
20336 target = Roo.get(target).dom.parentNode;
20339 var nodeName = target.nodeName;
20340 var className = target.className;
20341 var html = target.innerHTML;
20343 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20347 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20349 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20355 picker : function()
20357 return this.pickerEl;
20360 fillMonths: function()
20363 var months = this.picker().select('>.datepicker-months td', true).first();
20365 months.dom.innerHTML = '';
20371 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20374 months.createChild(month);
20383 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20384 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20387 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20388 e.removeClass('active');
20390 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20391 e.addClass('active');
20398 if(this.isInline) {
20402 this.picker().removeClass(['bottom', 'top']);
20404 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20406 * place to the top of element!
20410 this.picker().addClass('top');
20411 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20416 this.picker().addClass('bottom');
20418 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20421 onFocus : function()
20423 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20427 onBlur : function()
20429 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20431 var d = this.inputEl().getValue();
20440 this.picker().show();
20441 this.picker().select('>.datepicker-months', true).first().show();
20445 this.fireEvent('show', this, this.date);
20450 if(this.isInline) {
20453 this.picker().hide();
20454 this.fireEvent('hide', this, this.date);
20458 onMousedown: function(e)
20460 e.stopPropagation();
20461 e.preventDefault();
20466 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20470 fireKey: function(e)
20472 if (!this.picker().isVisible()){
20473 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20484 e.preventDefault();
20488 dir = e.keyCode == 37 ? -1 : 1;
20490 this.vIndex = this.vIndex + dir;
20492 if(this.vIndex < 0){
20496 if(this.vIndex > 11){
20500 if(isNaN(this.vIndex)){
20504 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20510 dir = e.keyCode == 38 ? -1 : 1;
20512 this.vIndex = this.vIndex + dir * 4;
20514 if(this.vIndex < 0){
20518 if(this.vIndex > 11){
20522 if(isNaN(this.vIndex)){
20526 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20531 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20532 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20536 e.preventDefault();
20539 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20540 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20556 this.picker().remove();
20561 Roo.apply(Roo.bootstrap.MonthField, {
20580 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20581 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20586 Roo.apply(Roo.bootstrap.MonthField, {
20590 cls: 'datepicker dropdown-menu roo-dynamic',
20594 cls: 'datepicker-months',
20598 cls: 'table-condensed',
20600 Roo.bootstrap.DateField.content
20620 * @class Roo.bootstrap.CheckBox
20621 * @extends Roo.bootstrap.Input
20622 * Bootstrap CheckBox class
20624 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20625 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20626 * @cfg {String} boxLabel The text that appears beside the checkbox
20627 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20628 * @cfg {Boolean} checked initnal the element
20629 * @cfg {Boolean} inline inline the element (default false)
20630 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20631 * @cfg {String} tooltip label tooltip
20634 * Create a new CheckBox
20635 * @param {Object} config The config object
20638 Roo.bootstrap.CheckBox = function(config){
20639 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20644 * Fires when the element is checked or unchecked.
20645 * @param {Roo.bootstrap.CheckBox} this This input
20646 * @param {Boolean} checked The new checked value
20651 * Fires when the element is click.
20652 * @param {Roo.bootstrap.CheckBox} this This input
20659 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20661 inputType: 'checkbox',
20670 getAutoCreate : function()
20672 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20678 cfg.cls = 'form-group ' + this.inputType; //input-group
20681 cfg.cls += ' ' + this.inputType + '-inline';
20687 type : this.inputType,
20688 value : this.inputValue,
20689 cls : 'roo-' + this.inputType, //'form-box',
20690 placeholder : this.placeholder || ''
20694 if(this.inputType != 'radio'){
20698 cls : 'roo-hidden-value',
20699 value : this.checked ? this.inputValue : this.valueOff
20704 if (this.weight) { // Validity check?
20705 cfg.cls += " " + this.inputType + "-" + this.weight;
20708 if (this.disabled) {
20709 input.disabled=true;
20713 input.checked = this.checked;
20718 input.name = this.name;
20720 if(this.inputType != 'radio'){
20721 hidden.name = this.name;
20722 input.name = '_hidden_' + this.name;
20727 input.cls += ' input-' + this.size;
20732 ['xs','sm','md','lg'].map(function(size){
20733 if (settings[size]) {
20734 cfg.cls += ' col-' + size + '-' + settings[size];
20738 var inputblock = input;
20740 if (this.before || this.after) {
20743 cls : 'input-group',
20748 inputblock.cn.push({
20750 cls : 'input-group-addon',
20755 inputblock.cn.push(input);
20757 if(this.inputType != 'radio'){
20758 inputblock.cn.push(hidden);
20762 inputblock.cn.push({
20764 cls : 'input-group-addon',
20771 if (align ==='left' && this.fieldLabel.length) {
20772 // Roo.log("left and has label");
20777 cls : 'control-label',
20778 html : this.fieldLabel
20788 if(this.labelWidth > 12){
20789 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20792 if(this.labelWidth < 13 && this.labelmd == 0){
20793 this.labelmd = this.labelWidth;
20796 if(this.labellg > 0){
20797 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20798 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20801 if(this.labelmd > 0){
20802 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20803 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20806 if(this.labelsm > 0){
20807 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20808 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20811 if(this.labelxs > 0){
20812 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20813 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20816 } else if ( this.fieldLabel.length) {
20817 // Roo.log(" label");
20821 tag: this.boxLabel ? 'span' : 'label',
20823 cls: 'control-label box-input-label',
20824 //cls : 'input-group-addon',
20825 html : this.fieldLabel
20834 // Roo.log(" no label && no align");
20835 cfg.cn = [ inputblock ] ;
20841 var boxLabelCfg = {
20843 //'for': id, // box label is handled by onclick - so no for...
20845 html: this.boxLabel
20849 boxLabelCfg.tooltip = this.tooltip;
20852 cfg.cn.push(boxLabelCfg);
20855 if(this.inputType != 'radio'){
20856 cfg.cn.push(hidden);
20864 * return the real input element.
20866 inputEl: function ()
20868 return this.el.select('input.roo-' + this.inputType,true).first();
20870 hiddenEl: function ()
20872 return this.el.select('input.roo-hidden-value',true).first();
20875 labelEl: function()
20877 return this.el.select('label.control-label',true).first();
20879 /* depricated... */
20883 return this.labelEl();
20886 boxLabelEl: function()
20888 return this.el.select('label.box-label',true).first();
20891 initEvents : function()
20893 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20895 this.inputEl().on('click', this.onClick, this);
20897 if (this.boxLabel) {
20898 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20901 this.startValue = this.getValue();
20904 Roo.bootstrap.CheckBox.register(this);
20908 onClick : function(e)
20910 if(this.fireEvent('click', this, e) !== false){
20911 this.setChecked(!this.checked);
20916 setChecked : function(state,suppressEvent)
20918 this.startValue = this.getValue();
20920 if(this.inputType == 'radio'){
20922 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20923 e.dom.checked = false;
20926 this.inputEl().dom.checked = true;
20928 this.inputEl().dom.value = this.inputValue;
20930 if(suppressEvent !== true){
20931 this.fireEvent('check', this, true);
20939 this.checked = state;
20941 this.inputEl().dom.checked = state;
20944 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20946 if(suppressEvent !== true){
20947 this.fireEvent('check', this, state);
20953 getValue : function()
20955 if(this.inputType == 'radio'){
20956 return this.getGroupValue();
20959 return this.hiddenEl().dom.value;
20963 getGroupValue : function()
20965 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20969 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20972 setValue : function(v,suppressEvent)
20974 if(this.inputType == 'radio'){
20975 this.setGroupValue(v, suppressEvent);
20979 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20984 setGroupValue : function(v, suppressEvent)
20986 this.startValue = this.getValue();
20988 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20989 e.dom.checked = false;
20991 if(e.dom.value == v){
20992 e.dom.checked = true;
20996 if(suppressEvent !== true){
20997 this.fireEvent('check', this, true);
21005 validate : function()
21007 if(this.getVisibilityEl().hasClass('hidden')){
21013 (this.inputType == 'radio' && this.validateRadio()) ||
21014 (this.inputType == 'checkbox' && this.validateCheckbox())
21020 this.markInvalid();
21024 validateRadio : function()
21026 if(this.getVisibilityEl().hasClass('hidden')){
21030 if(this.allowBlank){
21036 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21037 if(!e.dom.checked){
21049 validateCheckbox : function()
21052 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21053 //return (this.getValue() == this.inputValue) ? true : false;
21056 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21064 for(var i in group){
21065 if(group[i].el.isVisible(true)){
21073 for(var i in group){
21078 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21085 * Mark this field as valid
21087 markValid : function()
21091 this.fireEvent('valid', this);
21093 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21096 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21103 if(this.inputType == 'radio'){
21104 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21105 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21106 e.findParent('.form-group', false, true).addClass(_this.validClass);
21113 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21114 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21118 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21124 for(var i in group){
21125 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21126 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21131 * Mark this field as invalid
21132 * @param {String} msg The validation message
21134 markInvalid : function(msg)
21136 if(this.allowBlank){
21142 this.fireEvent('invalid', this, msg);
21144 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21147 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21151 label.markInvalid();
21154 if(this.inputType == 'radio'){
21155 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21156 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21157 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21164 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21165 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21169 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21175 for(var i in group){
21176 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21177 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21182 clearInvalid : function()
21184 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21186 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21188 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21190 if (label && label.iconEl) {
21191 label.iconEl.removeClass(label.validClass);
21192 label.iconEl.removeClass(label.invalidClass);
21196 disable : function()
21198 if(this.inputType != 'radio'){
21199 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21206 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21207 _this.getActionEl().addClass(this.disabledClass);
21208 e.dom.disabled = true;
21212 this.disabled = true;
21213 this.fireEvent("disable", this);
21217 enable : function()
21219 if(this.inputType != 'radio'){
21220 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21227 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21228 _this.getActionEl().removeClass(this.disabledClass);
21229 e.dom.disabled = false;
21233 this.disabled = false;
21234 this.fireEvent("enable", this);
21238 setBoxLabel : function(v)
21243 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21249 Roo.apply(Roo.bootstrap.CheckBox, {
21254 * register a CheckBox Group
21255 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21257 register : function(checkbox)
21259 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21260 this.groups[checkbox.groupId] = {};
21263 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21267 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21271 * fetch a CheckBox Group based on the group ID
21272 * @param {string} the group ID
21273 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21275 get: function(groupId) {
21276 if (typeof(this.groups[groupId]) == 'undefined') {
21280 return this.groups[groupId] ;
21293 * @class Roo.bootstrap.Radio
21294 * @extends Roo.bootstrap.Component
21295 * Bootstrap Radio class
21296 * @cfg {String} boxLabel - the label associated
21297 * @cfg {String} value - the value of radio
21300 * Create a new Radio
21301 * @param {Object} config The config object
21303 Roo.bootstrap.Radio = function(config){
21304 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21308 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21314 getAutoCreate : function()
21318 cls : 'form-group radio',
21323 html : this.boxLabel
21331 initEvents : function()
21333 this.parent().register(this);
21335 this.el.on('click', this.onClick, this);
21339 onClick : function(e)
21341 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21342 this.setChecked(true);
21346 setChecked : function(state, suppressEvent)
21348 this.parent().setValue(this.value, suppressEvent);
21352 setBoxLabel : function(v)
21357 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21372 * @class Roo.bootstrap.SecurePass
21373 * @extends Roo.bootstrap.Input
21374 * Bootstrap SecurePass class
21378 * Create a new SecurePass
21379 * @param {Object} config The config object
21382 Roo.bootstrap.SecurePass = function (config) {
21383 // these go here, so the translation tool can replace them..
21385 PwdEmpty: "Please type a password, and then retype it to confirm.",
21386 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21387 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21388 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21389 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21390 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21391 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21392 TooWeak: "Your password is Too Weak."
21394 this.meterLabel = "Password strength:";
21395 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21396 this.meterClass = [
21397 "roo-password-meter-tooweak",
21398 "roo-password-meter-weak",
21399 "roo-password-meter-medium",
21400 "roo-password-meter-strong",
21401 "roo-password-meter-grey"
21406 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21409 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21411 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21413 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21414 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21415 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21416 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21417 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21418 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21419 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21429 * @cfg {String/Object} Label for the strength meter (defaults to
21430 * 'Password strength:')
21435 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21436 * ['Weak', 'Medium', 'Strong'])
21439 pwdStrengths: false,
21452 initEvents: function ()
21454 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21456 if (this.el.is('input[type=password]') && Roo.isSafari) {
21457 this.el.on('keydown', this.SafariOnKeyDown, this);
21460 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21463 onRender: function (ct, position)
21465 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21466 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21467 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21469 this.trigger.createChild({
21474 cls: 'roo-password-meter-grey col-xs-12',
21477 //width: this.meterWidth + 'px'
21481 cls: 'roo-password-meter-text'
21487 if (this.hideTrigger) {
21488 this.trigger.setDisplayed(false);
21490 this.setSize(this.width || '', this.height || '');
21493 onDestroy: function ()
21495 if (this.trigger) {
21496 this.trigger.removeAllListeners();
21497 this.trigger.remove();
21500 this.wrap.remove();
21502 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21505 checkStrength: function ()
21507 var pwd = this.inputEl().getValue();
21508 if (pwd == this._lastPwd) {
21513 if (this.ClientSideStrongPassword(pwd)) {
21515 } else if (this.ClientSideMediumPassword(pwd)) {
21517 } else if (this.ClientSideWeakPassword(pwd)) {
21523 Roo.log('strength1: ' + strength);
21525 //var pm = this.trigger.child('div/div/div').dom;
21526 var pm = this.trigger.child('div/div');
21527 pm.removeClass(this.meterClass);
21528 pm.addClass(this.meterClass[strength]);
21531 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21533 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21535 this._lastPwd = pwd;
21539 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21541 this._lastPwd = '';
21543 var pm = this.trigger.child('div/div');
21544 pm.removeClass(this.meterClass);
21545 pm.addClass('roo-password-meter-grey');
21548 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21551 this.inputEl().dom.type='password';
21554 validateValue: function (value)
21557 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21560 if (value.length == 0) {
21561 if (this.allowBlank) {
21562 this.clearInvalid();
21566 this.markInvalid(this.errors.PwdEmpty);
21567 this.errorMsg = this.errors.PwdEmpty;
21575 if ('[\x21-\x7e]*'.match(value)) {
21576 this.markInvalid(this.errors.PwdBadChar);
21577 this.errorMsg = this.errors.PwdBadChar;
21580 if (value.length < 6) {
21581 this.markInvalid(this.errors.PwdShort);
21582 this.errorMsg = this.errors.PwdShort;
21585 if (value.length > 16) {
21586 this.markInvalid(this.errors.PwdLong);
21587 this.errorMsg = this.errors.PwdLong;
21591 if (this.ClientSideStrongPassword(value)) {
21593 } else if (this.ClientSideMediumPassword(value)) {
21595 } else if (this.ClientSideWeakPassword(value)) {
21602 if (strength < 2) {
21603 //this.markInvalid(this.errors.TooWeak);
21604 this.errorMsg = this.errors.TooWeak;
21609 console.log('strength2: ' + strength);
21611 //var pm = this.trigger.child('div/div/div').dom;
21613 var pm = this.trigger.child('div/div');
21614 pm.removeClass(this.meterClass);
21615 pm.addClass(this.meterClass[strength]);
21617 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21619 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21621 this.errorMsg = '';
21625 CharacterSetChecks: function (type)
21628 this.fResult = false;
21631 isctype: function (character, type)
21634 case this.kCapitalLetter:
21635 if (character >= 'A' && character <= 'Z') {
21640 case this.kSmallLetter:
21641 if (character >= 'a' && character <= 'z') {
21647 if (character >= '0' && character <= '9') {
21652 case this.kPunctuation:
21653 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21664 IsLongEnough: function (pwd, size)
21666 return !(pwd == null || isNaN(size) || pwd.length < size);
21669 SpansEnoughCharacterSets: function (word, nb)
21671 if (!this.IsLongEnough(word, nb))
21676 var characterSetChecks = new Array(
21677 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21678 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21681 for (var index = 0; index < word.length; ++index) {
21682 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21683 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21684 characterSetChecks[nCharSet].fResult = true;
21691 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21692 if (characterSetChecks[nCharSet].fResult) {
21697 if (nCharSets < nb) {
21703 ClientSideStrongPassword: function (pwd)
21705 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21708 ClientSideMediumPassword: function (pwd)
21710 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21713 ClientSideWeakPassword: function (pwd)
21715 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21718 })//<script type="text/javascript">
21721 * Based Ext JS Library 1.1.1
21722 * Copyright(c) 2006-2007, Ext JS, LLC.
21728 * @class Roo.HtmlEditorCore
21729 * @extends Roo.Component
21730 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21732 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21735 Roo.HtmlEditorCore = function(config){
21738 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21743 * @event initialize
21744 * Fires when the editor is fully initialized (including the iframe)
21745 * @param {Roo.HtmlEditorCore} this
21750 * Fires when the editor is first receives the focus. Any insertion must wait
21751 * until after this event.
21752 * @param {Roo.HtmlEditorCore} this
21756 * @event beforesync
21757 * Fires before the textarea is updated with content from the editor iframe. Return false
21758 * to cancel the sync.
21759 * @param {Roo.HtmlEditorCore} this
21760 * @param {String} html
21764 * @event beforepush
21765 * Fires before the iframe editor is updated with content from the textarea. Return false
21766 * to cancel the push.
21767 * @param {Roo.HtmlEditorCore} this
21768 * @param {String} html
21773 * Fires when the textarea is updated with content from the editor iframe.
21774 * @param {Roo.HtmlEditorCore} this
21775 * @param {String} html
21780 * Fires when the iframe editor is updated with content from the textarea.
21781 * @param {Roo.HtmlEditorCore} this
21782 * @param {String} html
21787 * @event editorevent
21788 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21789 * @param {Roo.HtmlEditorCore} this
21795 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21797 // defaults : white / black...
21798 this.applyBlacklists();
21805 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21809 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21815 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21820 * @cfg {Number} height (in pixels)
21824 * @cfg {Number} width (in pixels)
21829 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21832 stylesheets: false,
21837 // private properties
21838 validationEvent : false,
21840 initialized : false,
21842 sourceEditMode : false,
21843 onFocus : Roo.emptyFn,
21845 hideMode:'offsets',
21849 // blacklist + whitelisted elements..
21856 * Protected method that will not generally be called directly. It
21857 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21858 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21860 getDocMarkup : function(){
21864 // inherit styels from page...??
21865 if (this.stylesheets === false) {
21867 Roo.get(document.head).select('style').each(function(node) {
21868 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21871 Roo.get(document.head).select('link').each(function(node) {
21872 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21875 } else if (!this.stylesheets.length) {
21877 st = '<style type="text/css">' +
21878 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21881 st = '<style type="text/css">' +
21886 st += '<style type="text/css">' +
21887 'IMG { cursor: pointer } ' +
21890 var cls = 'roo-htmleditor-body';
21892 if(this.bodyCls.length){
21893 cls += ' ' + this.bodyCls;
21896 return '<html><head>' + st +
21897 //<style type="text/css">' +
21898 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21900 ' </head><body class="' + cls + '"></body></html>';
21904 onRender : function(ct, position)
21907 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21908 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21911 this.el.dom.style.border = '0 none';
21912 this.el.dom.setAttribute('tabIndex', -1);
21913 this.el.addClass('x-hidden hide');
21917 if(Roo.isIE){ // fix IE 1px bogus margin
21918 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21922 this.frameId = Roo.id();
21926 var iframe = this.owner.wrap.createChild({
21928 cls: 'form-control', // bootstrap..
21930 name: this.frameId,
21931 frameBorder : 'no',
21932 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21937 this.iframe = iframe.dom;
21939 this.assignDocWin();
21941 this.doc.designMode = 'on';
21944 this.doc.write(this.getDocMarkup());
21948 var task = { // must defer to wait for browser to be ready
21950 //console.log("run task?" + this.doc.readyState);
21951 this.assignDocWin();
21952 if(this.doc.body || this.doc.readyState == 'complete'){
21954 this.doc.designMode="on";
21958 Roo.TaskMgr.stop(task);
21959 this.initEditor.defer(10, this);
21966 Roo.TaskMgr.start(task);
21971 onResize : function(w, h)
21973 Roo.log('resize: ' +w + ',' + h );
21974 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21978 if(typeof w == 'number'){
21980 this.iframe.style.width = w + 'px';
21982 if(typeof h == 'number'){
21984 this.iframe.style.height = h + 'px';
21986 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21993 * Toggles the editor between standard and source edit mode.
21994 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21996 toggleSourceEdit : function(sourceEditMode){
21998 this.sourceEditMode = sourceEditMode === true;
22000 if(this.sourceEditMode){
22002 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22005 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22006 //this.iframe.className = '';
22009 //this.setSize(this.owner.wrap.getSize());
22010 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22017 * Protected method that will not generally be called directly. If you need/want
22018 * custom HTML cleanup, this is the method you should override.
22019 * @param {String} html The HTML to be cleaned
22020 * return {String} The cleaned HTML
22022 cleanHtml : function(html){
22023 html = String(html);
22024 if(html.length > 5){
22025 if(Roo.isSafari){ // strip safari nonsense
22026 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22029 if(html == ' '){
22036 * HTML Editor -> Textarea
22037 * Protected method that will not generally be called directly. Syncs the contents
22038 * of the editor iframe with the textarea.
22040 syncValue : function(){
22041 if(this.initialized){
22042 var bd = (this.doc.body || this.doc.documentElement);
22043 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22044 var html = bd.innerHTML;
22046 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22047 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22049 html = '<div style="'+m[0]+'">' + html + '</div>';
22052 html = this.cleanHtml(html);
22053 // fix up the special chars.. normaly like back quotes in word...
22054 // however we do not want to do this with chinese..
22055 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22056 var cc = b.charCodeAt();
22058 (cc >= 0x4E00 && cc < 0xA000 ) ||
22059 (cc >= 0x3400 && cc < 0x4E00 ) ||
22060 (cc >= 0xf900 && cc < 0xfb00 )
22066 if(this.owner.fireEvent('beforesync', this, html) !== false){
22067 this.el.dom.value = html;
22068 this.owner.fireEvent('sync', this, html);
22074 * Protected method that will not generally be called directly. Pushes the value of the textarea
22075 * into the iframe editor.
22077 pushValue : function(){
22078 if(this.initialized){
22079 var v = this.el.dom.value.trim();
22081 // if(v.length < 1){
22085 if(this.owner.fireEvent('beforepush', this, v) !== false){
22086 var d = (this.doc.body || this.doc.documentElement);
22088 this.cleanUpPaste();
22089 this.el.dom.value = d.innerHTML;
22090 this.owner.fireEvent('push', this, v);
22096 deferFocus : function(){
22097 this.focus.defer(10, this);
22101 focus : function(){
22102 if(this.win && !this.sourceEditMode){
22109 assignDocWin: function()
22111 var iframe = this.iframe;
22114 this.doc = iframe.contentWindow.document;
22115 this.win = iframe.contentWindow;
22117 // if (!Roo.get(this.frameId)) {
22120 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22121 // this.win = Roo.get(this.frameId).dom.contentWindow;
22123 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22127 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22128 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22133 initEditor : function(){
22134 //console.log("INIT EDITOR");
22135 this.assignDocWin();
22139 this.doc.designMode="on";
22141 this.doc.write(this.getDocMarkup());
22144 var dbody = (this.doc.body || this.doc.documentElement);
22145 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22146 // this copies styles from the containing element into thsi one..
22147 // not sure why we need all of this..
22148 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22150 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22151 //ss['background-attachment'] = 'fixed'; // w3c
22152 dbody.bgProperties = 'fixed'; // ie
22153 //Roo.DomHelper.applyStyles(dbody, ss);
22154 Roo.EventManager.on(this.doc, {
22155 //'mousedown': this.onEditorEvent,
22156 'mouseup': this.onEditorEvent,
22157 'dblclick': this.onEditorEvent,
22158 'click': this.onEditorEvent,
22159 'keyup': this.onEditorEvent,
22164 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22166 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22167 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22169 this.initialized = true;
22171 this.owner.fireEvent('initialize', this);
22176 onDestroy : function(){
22182 //for (var i =0; i < this.toolbars.length;i++) {
22183 // // fixme - ask toolbars for heights?
22184 // this.toolbars[i].onDestroy();
22187 //this.wrap.dom.innerHTML = '';
22188 //this.wrap.remove();
22193 onFirstFocus : function(){
22195 this.assignDocWin();
22198 this.activated = true;
22201 if(Roo.isGecko){ // prevent silly gecko errors
22203 var s = this.win.getSelection();
22204 if(!s.focusNode || s.focusNode.nodeType != 3){
22205 var r = s.getRangeAt(0);
22206 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22211 this.execCmd('useCSS', true);
22212 this.execCmd('styleWithCSS', false);
22215 this.owner.fireEvent('activate', this);
22219 adjustFont: function(btn){
22220 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22221 //if(Roo.isSafari){ // safari
22224 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22225 if(Roo.isSafari){ // safari
22226 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22227 v = (v < 10) ? 10 : v;
22228 v = (v > 48) ? 48 : v;
22229 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22234 v = Math.max(1, v+adjust);
22236 this.execCmd('FontSize', v );
22239 onEditorEvent : function(e)
22241 this.owner.fireEvent('editorevent', this, e);
22242 // this.updateToolbar();
22243 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22246 insertTag : function(tg)
22248 // could be a bit smarter... -> wrap the current selected tRoo..
22249 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22251 range = this.createRange(this.getSelection());
22252 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22253 wrappingNode.appendChild(range.extractContents());
22254 range.insertNode(wrappingNode);
22261 this.execCmd("formatblock", tg);
22265 insertText : function(txt)
22269 var range = this.createRange();
22270 range.deleteContents();
22271 //alert(Sender.getAttribute('label'));
22273 range.insertNode(this.doc.createTextNode(txt));
22279 * Executes a Midas editor command on the editor document and performs necessary focus and
22280 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22281 * @param {String} cmd The Midas command
22282 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22284 relayCmd : function(cmd, value){
22286 this.execCmd(cmd, value);
22287 this.owner.fireEvent('editorevent', this);
22288 //this.updateToolbar();
22289 this.owner.deferFocus();
22293 * Executes a Midas editor command directly on the editor document.
22294 * For visual commands, you should use {@link #relayCmd} instead.
22295 * <b>This should only be called after the editor is initialized.</b>
22296 * @param {String} cmd The Midas command
22297 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22299 execCmd : function(cmd, value){
22300 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22307 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22309 * @param {String} text | dom node..
22311 insertAtCursor : function(text)
22314 if(!this.activated){
22320 var r = this.doc.selection.createRange();
22331 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22335 // from jquery ui (MIT licenced)
22337 var win = this.win;
22339 if (win.getSelection && win.getSelection().getRangeAt) {
22340 range = win.getSelection().getRangeAt(0);
22341 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22342 range.insertNode(node);
22343 } else if (win.document.selection && win.document.selection.createRange) {
22344 // no firefox support
22345 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22346 win.document.selection.createRange().pasteHTML(txt);
22348 // no firefox support
22349 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22350 this.execCmd('InsertHTML', txt);
22359 mozKeyPress : function(e){
22361 var c = e.getCharCode(), cmd;
22364 c = String.fromCharCode(c).toLowerCase();
22378 this.cleanUpPaste.defer(100, this);
22386 e.preventDefault();
22394 fixKeys : function(){ // load time branching for fastest keydown performance
22396 return function(e){
22397 var k = e.getKey(), r;
22400 r = this.doc.selection.createRange();
22403 r.pasteHTML('    ');
22410 r = this.doc.selection.createRange();
22412 var target = r.parentElement();
22413 if(!target || target.tagName.toLowerCase() != 'li'){
22415 r.pasteHTML('<br />');
22421 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22422 this.cleanUpPaste.defer(100, this);
22428 }else if(Roo.isOpera){
22429 return function(e){
22430 var k = e.getKey();
22434 this.execCmd('InsertHTML','    ');
22437 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22438 this.cleanUpPaste.defer(100, this);
22443 }else if(Roo.isSafari){
22444 return function(e){
22445 var k = e.getKey();
22449 this.execCmd('InsertText','\t');
22453 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22454 this.cleanUpPaste.defer(100, this);
22462 getAllAncestors: function()
22464 var p = this.getSelectedNode();
22467 a.push(p); // push blank onto stack..
22468 p = this.getParentElement();
22472 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22476 a.push(this.doc.body);
22480 lastSelNode : false,
22483 getSelection : function()
22485 this.assignDocWin();
22486 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22489 getSelectedNode: function()
22491 // this may only work on Gecko!!!
22493 // should we cache this!!!!
22498 var range = this.createRange(this.getSelection()).cloneRange();
22501 var parent = range.parentElement();
22503 var testRange = range.duplicate();
22504 testRange.moveToElementText(parent);
22505 if (testRange.inRange(range)) {
22508 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22511 parent = parent.parentElement;
22516 // is ancestor a text element.
22517 var ac = range.commonAncestorContainer;
22518 if (ac.nodeType == 3) {
22519 ac = ac.parentNode;
22522 var ar = ac.childNodes;
22525 var other_nodes = [];
22526 var has_other_nodes = false;
22527 for (var i=0;i<ar.length;i++) {
22528 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22531 // fullly contained node.
22533 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22538 // probably selected..
22539 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22540 other_nodes.push(ar[i]);
22544 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22549 has_other_nodes = true;
22551 if (!nodes.length && other_nodes.length) {
22552 nodes= other_nodes;
22554 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22560 createRange: function(sel)
22562 // this has strange effects when using with
22563 // top toolbar - not sure if it's a great idea.
22564 //this.editor.contentWindow.focus();
22565 if (typeof sel != "undefined") {
22567 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22569 return this.doc.createRange();
22572 return this.doc.createRange();
22575 getParentElement: function()
22578 this.assignDocWin();
22579 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22581 var range = this.createRange(sel);
22584 var p = range.commonAncestorContainer;
22585 while (p.nodeType == 3) { // text node
22596 * Range intersection.. the hard stuff...
22600 * [ -- selected range --- ]
22604 * if end is before start or hits it. fail.
22605 * if start is after end or hits it fail.
22607 * if either hits (but other is outside. - then it's not
22613 // @see http://www.thismuchiknow.co.uk/?p=64.
22614 rangeIntersectsNode : function(range, node)
22616 var nodeRange = node.ownerDocument.createRange();
22618 nodeRange.selectNode(node);
22620 nodeRange.selectNodeContents(node);
22623 var rangeStartRange = range.cloneRange();
22624 rangeStartRange.collapse(true);
22626 var rangeEndRange = range.cloneRange();
22627 rangeEndRange.collapse(false);
22629 var nodeStartRange = nodeRange.cloneRange();
22630 nodeStartRange.collapse(true);
22632 var nodeEndRange = nodeRange.cloneRange();
22633 nodeEndRange.collapse(false);
22635 return rangeStartRange.compareBoundaryPoints(
22636 Range.START_TO_START, nodeEndRange) == -1 &&
22637 rangeEndRange.compareBoundaryPoints(
22638 Range.START_TO_START, nodeStartRange) == 1;
22642 rangeCompareNode : function(range, node)
22644 var nodeRange = node.ownerDocument.createRange();
22646 nodeRange.selectNode(node);
22648 nodeRange.selectNodeContents(node);
22652 range.collapse(true);
22654 nodeRange.collapse(true);
22656 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22657 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22659 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22661 var nodeIsBefore = ss == 1;
22662 var nodeIsAfter = ee == -1;
22664 if (nodeIsBefore && nodeIsAfter) {
22667 if (!nodeIsBefore && nodeIsAfter) {
22668 return 1; //right trailed.
22671 if (nodeIsBefore && !nodeIsAfter) {
22672 return 2; // left trailed.
22678 // private? - in a new class?
22679 cleanUpPaste : function()
22681 // cleans up the whole document..
22682 Roo.log('cleanuppaste');
22684 this.cleanUpChildren(this.doc.body);
22685 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22686 if (clean != this.doc.body.innerHTML) {
22687 this.doc.body.innerHTML = clean;
22692 cleanWordChars : function(input) {// change the chars to hex code
22693 var he = Roo.HtmlEditorCore;
22695 var output = input;
22696 Roo.each(he.swapCodes, function(sw) {
22697 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22699 output = output.replace(swapper, sw[1]);
22706 cleanUpChildren : function (n)
22708 if (!n.childNodes.length) {
22711 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22712 this.cleanUpChild(n.childNodes[i]);
22719 cleanUpChild : function (node)
22722 //console.log(node);
22723 if (node.nodeName == "#text") {
22724 // clean up silly Windows -- stuff?
22727 if (node.nodeName == "#comment") {
22728 node.parentNode.removeChild(node);
22729 // clean up silly Windows -- stuff?
22732 var lcname = node.tagName.toLowerCase();
22733 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22734 // whitelist of tags..
22736 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22738 node.parentNode.removeChild(node);
22743 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22745 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22746 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22748 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22749 // remove_keep_children = true;
22752 if (remove_keep_children) {
22753 this.cleanUpChildren(node);
22754 // inserts everything just before this node...
22755 while (node.childNodes.length) {
22756 var cn = node.childNodes[0];
22757 node.removeChild(cn);
22758 node.parentNode.insertBefore(cn, node);
22760 node.parentNode.removeChild(node);
22764 if (!node.attributes || !node.attributes.length) {
22765 this.cleanUpChildren(node);
22769 function cleanAttr(n,v)
22772 if (v.match(/^\./) || v.match(/^\//)) {
22775 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22778 if (v.match(/^#/)) {
22781 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22782 node.removeAttribute(n);
22786 var cwhite = this.cwhite;
22787 var cblack = this.cblack;
22789 function cleanStyle(n,v)
22791 if (v.match(/expression/)) { //XSS?? should we even bother..
22792 node.removeAttribute(n);
22796 var parts = v.split(/;/);
22799 Roo.each(parts, function(p) {
22800 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22804 var l = p.split(':').shift().replace(/\s+/g,'');
22805 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22807 if ( cwhite.length && cblack.indexOf(l) > -1) {
22808 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22809 //node.removeAttribute(n);
22813 // only allow 'c whitelisted system attributes'
22814 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22815 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22816 //node.removeAttribute(n);
22826 if (clean.length) {
22827 node.setAttribute(n, clean.join(';'));
22829 node.removeAttribute(n);
22835 for (var i = node.attributes.length-1; i > -1 ; i--) {
22836 var a = node.attributes[i];
22839 if (a.name.toLowerCase().substr(0,2)=='on') {
22840 node.removeAttribute(a.name);
22843 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22844 node.removeAttribute(a.name);
22847 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22848 cleanAttr(a.name,a.value); // fixme..
22851 if (a.name == 'style') {
22852 cleanStyle(a.name,a.value);
22855 /// clean up MS crap..
22856 // tecnically this should be a list of valid class'es..
22859 if (a.name == 'class') {
22860 if (a.value.match(/^Mso/)) {
22861 node.className = '';
22864 if (a.value.match(/^body$/)) {
22865 node.className = '';
22876 this.cleanUpChildren(node);
22882 * Clean up MS wordisms...
22884 cleanWord : function(node)
22889 this.cleanWord(this.doc.body);
22892 if (node.nodeName == "#text") {
22893 // clean up silly Windows -- stuff?
22896 if (node.nodeName == "#comment") {
22897 node.parentNode.removeChild(node);
22898 // clean up silly Windows -- stuff?
22902 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22903 node.parentNode.removeChild(node);
22907 // remove - but keep children..
22908 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22909 while (node.childNodes.length) {
22910 var cn = node.childNodes[0];
22911 node.removeChild(cn);
22912 node.parentNode.insertBefore(cn, node);
22914 node.parentNode.removeChild(node);
22915 this.iterateChildren(node, this.cleanWord);
22919 if (node.className.length) {
22921 var cn = node.className.split(/\W+/);
22923 Roo.each(cn, function(cls) {
22924 if (cls.match(/Mso[a-zA-Z]+/)) {
22929 node.className = cna.length ? cna.join(' ') : '';
22931 node.removeAttribute("class");
22935 if (node.hasAttribute("lang")) {
22936 node.removeAttribute("lang");
22939 if (node.hasAttribute("style")) {
22941 var styles = node.getAttribute("style").split(";");
22943 Roo.each(styles, function(s) {
22944 if (!s.match(/:/)) {
22947 var kv = s.split(":");
22948 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22951 // what ever is left... we allow.
22954 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22955 if (!nstyle.length) {
22956 node.removeAttribute('style');
22959 this.iterateChildren(node, this.cleanWord);
22965 * iterateChildren of a Node, calling fn each time, using this as the scole..
22966 * @param {DomNode} node node to iterate children of.
22967 * @param {Function} fn method of this class to call on each item.
22969 iterateChildren : function(node, fn)
22971 if (!node.childNodes.length) {
22974 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22975 fn.call(this, node.childNodes[i])
22981 * cleanTableWidths.
22983 * Quite often pasting from word etc.. results in tables with column and widths.
22984 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22987 cleanTableWidths : function(node)
22992 this.cleanTableWidths(this.doc.body);
22997 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23000 Roo.log(node.tagName);
23001 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23002 this.iterateChildren(node, this.cleanTableWidths);
23005 if (node.hasAttribute('width')) {
23006 node.removeAttribute('width');
23010 if (node.hasAttribute("style")) {
23013 var styles = node.getAttribute("style").split(";");
23015 Roo.each(styles, function(s) {
23016 if (!s.match(/:/)) {
23019 var kv = s.split(":");
23020 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23023 // what ever is left... we allow.
23026 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23027 if (!nstyle.length) {
23028 node.removeAttribute('style');
23032 this.iterateChildren(node, this.cleanTableWidths);
23040 domToHTML : function(currentElement, depth, nopadtext) {
23042 depth = depth || 0;
23043 nopadtext = nopadtext || false;
23045 if (!currentElement) {
23046 return this.domToHTML(this.doc.body);
23049 //Roo.log(currentElement);
23051 var allText = false;
23052 var nodeName = currentElement.nodeName;
23053 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23055 if (nodeName == '#text') {
23057 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23062 if (nodeName != 'BODY') {
23065 // Prints the node tagName, such as <A>, <IMG>, etc
23068 for(i = 0; i < currentElement.attributes.length;i++) {
23070 var aname = currentElement.attributes.item(i).name;
23071 if (!currentElement.attributes.item(i).value.length) {
23074 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23077 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23086 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23089 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23094 // Traverse the tree
23096 var currentElementChild = currentElement.childNodes.item(i);
23097 var allText = true;
23098 var innerHTML = '';
23100 while (currentElementChild) {
23101 // Formatting code (indent the tree so it looks nice on the screen)
23102 var nopad = nopadtext;
23103 if (lastnode == 'SPAN') {
23107 if (currentElementChild.nodeName == '#text') {
23108 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23109 toadd = nopadtext ? toadd : toadd.trim();
23110 if (!nopad && toadd.length > 80) {
23111 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23113 innerHTML += toadd;
23116 currentElementChild = currentElement.childNodes.item(i);
23122 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23124 // Recursively traverse the tree structure of the child node
23125 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23126 lastnode = currentElementChild.nodeName;
23128 currentElementChild=currentElement.childNodes.item(i);
23134 // The remaining code is mostly for formatting the tree
23135 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23140 ret+= "</"+tagName+">";
23146 applyBlacklists : function()
23148 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23149 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23153 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23154 if (b.indexOf(tag) > -1) {
23157 this.white.push(tag);
23161 Roo.each(w, function(tag) {
23162 if (b.indexOf(tag) > -1) {
23165 if (this.white.indexOf(tag) > -1) {
23168 this.white.push(tag);
23173 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23174 if (w.indexOf(tag) > -1) {
23177 this.black.push(tag);
23181 Roo.each(b, function(tag) {
23182 if (w.indexOf(tag) > -1) {
23185 if (this.black.indexOf(tag) > -1) {
23188 this.black.push(tag);
23193 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23194 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23198 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23199 if (b.indexOf(tag) > -1) {
23202 this.cwhite.push(tag);
23206 Roo.each(w, function(tag) {
23207 if (b.indexOf(tag) > -1) {
23210 if (this.cwhite.indexOf(tag) > -1) {
23213 this.cwhite.push(tag);
23218 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23219 if (w.indexOf(tag) > -1) {
23222 this.cblack.push(tag);
23226 Roo.each(b, function(tag) {
23227 if (w.indexOf(tag) > -1) {
23230 if (this.cblack.indexOf(tag) > -1) {
23233 this.cblack.push(tag);
23238 setStylesheets : function(stylesheets)
23240 if(typeof(stylesheets) == 'string'){
23241 Roo.get(this.iframe.contentDocument.head).createChild({
23243 rel : 'stylesheet',
23252 Roo.each(stylesheets, function(s) {
23257 Roo.get(_this.iframe.contentDocument.head).createChild({
23259 rel : 'stylesheet',
23268 removeStylesheets : function()
23272 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23277 setStyle : function(style)
23279 Roo.get(this.iframe.contentDocument.head).createChild({
23288 // hide stuff that is not compatible
23302 * @event specialkey
23306 * @cfg {String} fieldClass @hide
23309 * @cfg {String} focusClass @hide
23312 * @cfg {String} autoCreate @hide
23315 * @cfg {String} inputType @hide
23318 * @cfg {String} invalidClass @hide
23321 * @cfg {String} invalidText @hide
23324 * @cfg {String} msgFx @hide
23327 * @cfg {String} validateOnBlur @hide
23331 Roo.HtmlEditorCore.white = [
23332 'area', 'br', 'img', 'input', 'hr', 'wbr',
23334 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23335 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23336 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23337 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23338 'table', 'ul', 'xmp',
23340 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23343 'dir', 'menu', 'ol', 'ul', 'dl',
23349 Roo.HtmlEditorCore.black = [
23350 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23352 'base', 'basefont', 'bgsound', 'blink', 'body',
23353 'frame', 'frameset', 'head', 'html', 'ilayer',
23354 'iframe', 'layer', 'link', 'meta', 'object',
23355 'script', 'style' ,'title', 'xml' // clean later..
23357 Roo.HtmlEditorCore.clean = [
23358 'script', 'style', 'title', 'xml'
23360 Roo.HtmlEditorCore.remove = [
23365 Roo.HtmlEditorCore.ablack = [
23369 Roo.HtmlEditorCore.aclean = [
23370 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23374 Roo.HtmlEditorCore.pwhite= [
23375 'http', 'https', 'mailto'
23378 // white listed style attributes.
23379 Roo.HtmlEditorCore.cwhite= [
23380 // 'text-align', /// default is to allow most things..
23386 // black listed style attributes.
23387 Roo.HtmlEditorCore.cblack= [
23388 // 'font-size' -- this can be set by the project
23392 Roo.HtmlEditorCore.swapCodes =[
23411 * @class Roo.bootstrap.HtmlEditor
23412 * @extends Roo.bootstrap.TextArea
23413 * Bootstrap HtmlEditor class
23416 * Create a new HtmlEditor
23417 * @param {Object} config The config object
23420 Roo.bootstrap.HtmlEditor = function(config){
23421 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23422 if (!this.toolbars) {
23423 this.toolbars = [];
23426 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23429 * @event initialize
23430 * Fires when the editor is fully initialized (including the iframe)
23431 * @param {HtmlEditor} this
23436 * Fires when the editor is first receives the focus. Any insertion must wait
23437 * until after this event.
23438 * @param {HtmlEditor} this
23442 * @event beforesync
23443 * Fires before the textarea is updated with content from the editor iframe. Return false
23444 * to cancel the sync.
23445 * @param {HtmlEditor} this
23446 * @param {String} html
23450 * @event beforepush
23451 * Fires before the iframe editor is updated with content from the textarea. Return false
23452 * to cancel the push.
23453 * @param {HtmlEditor} this
23454 * @param {String} html
23459 * Fires when the textarea is updated with content from the editor iframe.
23460 * @param {HtmlEditor} this
23461 * @param {String} html
23466 * Fires when the iframe editor is updated with content from the textarea.
23467 * @param {HtmlEditor} this
23468 * @param {String} html
23472 * @event editmodechange
23473 * Fires when the editor switches edit modes
23474 * @param {HtmlEditor} this
23475 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23477 editmodechange: true,
23479 * @event editorevent
23480 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23481 * @param {HtmlEditor} this
23485 * @event firstfocus
23486 * Fires when on first focus - needed by toolbars..
23487 * @param {HtmlEditor} this
23492 * Auto save the htmlEditor value as a file into Events
23493 * @param {HtmlEditor} this
23497 * @event savedpreview
23498 * preview the saved version of htmlEditor
23499 * @param {HtmlEditor} this
23506 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23510 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23515 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23520 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23525 * @cfg {Number} height (in pixels)
23529 * @cfg {Number} width (in pixels)
23534 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23537 stylesheets: false,
23542 // private properties
23543 validationEvent : false,
23545 initialized : false,
23548 onFocus : Roo.emptyFn,
23550 hideMode:'offsets',
23552 tbContainer : false,
23556 toolbarContainer :function() {
23557 return this.wrap.select('.x-html-editor-tb',true).first();
23561 * Protected method that will not generally be called directly. It
23562 * is called when the editor creates its toolbar. Override this method if you need to
23563 * add custom toolbar buttons.
23564 * @param {HtmlEditor} editor
23566 createToolbar : function(){
23567 Roo.log('renewing');
23568 Roo.log("create toolbars");
23570 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23571 this.toolbars[0].render(this.toolbarContainer());
23575 // if (!editor.toolbars || !editor.toolbars.length) {
23576 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23579 // for (var i =0 ; i < editor.toolbars.length;i++) {
23580 // editor.toolbars[i] = Roo.factory(
23581 // typeof(editor.toolbars[i]) == 'string' ?
23582 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23583 // Roo.bootstrap.HtmlEditor);
23584 // editor.toolbars[i].init(editor);
23590 onRender : function(ct, position)
23592 // Roo.log("Call onRender: " + this.xtype);
23594 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23596 this.wrap = this.inputEl().wrap({
23597 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23600 this.editorcore.onRender(ct, position);
23602 if (this.resizable) {
23603 this.resizeEl = new Roo.Resizable(this.wrap, {
23607 minHeight : this.height,
23608 height: this.height,
23609 handles : this.resizable,
23612 resize : function(r, w, h) {
23613 _t.onResize(w,h); // -something
23619 this.createToolbar(this);
23622 if(!this.width && this.resizable){
23623 this.setSize(this.wrap.getSize());
23625 if (this.resizeEl) {
23626 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23627 // should trigger onReize..
23633 onResize : function(w, h)
23635 Roo.log('resize: ' +w + ',' + h );
23636 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23640 if(this.inputEl() ){
23641 if(typeof w == 'number'){
23642 var aw = w - this.wrap.getFrameWidth('lr');
23643 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23646 if(typeof h == 'number'){
23647 var tbh = -11; // fixme it needs to tool bar size!
23648 for (var i =0; i < this.toolbars.length;i++) {
23649 // fixme - ask toolbars for heights?
23650 tbh += this.toolbars[i].el.getHeight();
23651 //if (this.toolbars[i].footer) {
23652 // tbh += this.toolbars[i].footer.el.getHeight();
23660 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23661 ah -= 5; // knock a few pixes off for look..
23662 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23666 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23667 this.editorcore.onResize(ew,eh);
23672 * Toggles the editor between standard and source edit mode.
23673 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23675 toggleSourceEdit : function(sourceEditMode)
23677 this.editorcore.toggleSourceEdit(sourceEditMode);
23679 if(this.editorcore.sourceEditMode){
23680 Roo.log('editor - showing textarea');
23683 // Roo.log(this.syncValue());
23685 this.inputEl().removeClass(['hide', 'x-hidden']);
23686 this.inputEl().dom.removeAttribute('tabIndex');
23687 this.inputEl().focus();
23689 Roo.log('editor - hiding textarea');
23691 // Roo.log(this.pushValue());
23694 this.inputEl().addClass(['hide', 'x-hidden']);
23695 this.inputEl().dom.setAttribute('tabIndex', -1);
23696 //this.deferFocus();
23699 if(this.resizable){
23700 this.setSize(this.wrap.getSize());
23703 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23706 // private (for BoxComponent)
23707 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23709 // private (for BoxComponent)
23710 getResizeEl : function(){
23714 // private (for BoxComponent)
23715 getPositionEl : function(){
23720 initEvents : function(){
23721 this.originalValue = this.getValue();
23725 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23728 // markInvalid : Roo.emptyFn,
23730 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23733 // clearInvalid : Roo.emptyFn,
23735 setValue : function(v){
23736 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23737 this.editorcore.pushValue();
23742 deferFocus : function(){
23743 this.focus.defer(10, this);
23747 focus : function(){
23748 this.editorcore.focus();
23754 onDestroy : function(){
23760 for (var i =0; i < this.toolbars.length;i++) {
23761 // fixme - ask toolbars for heights?
23762 this.toolbars[i].onDestroy();
23765 this.wrap.dom.innerHTML = '';
23766 this.wrap.remove();
23771 onFirstFocus : function(){
23772 //Roo.log("onFirstFocus");
23773 this.editorcore.onFirstFocus();
23774 for (var i =0; i < this.toolbars.length;i++) {
23775 this.toolbars[i].onFirstFocus();
23781 syncValue : function()
23783 this.editorcore.syncValue();
23786 pushValue : function()
23788 this.editorcore.pushValue();
23792 // hide stuff that is not compatible
23806 * @event specialkey
23810 * @cfg {String} fieldClass @hide
23813 * @cfg {String} focusClass @hide
23816 * @cfg {String} autoCreate @hide
23819 * @cfg {String} inputType @hide
23822 * @cfg {String} invalidClass @hide
23825 * @cfg {String} invalidText @hide
23828 * @cfg {String} msgFx @hide
23831 * @cfg {String} validateOnBlur @hide
23840 Roo.namespace('Roo.bootstrap.htmleditor');
23842 * @class Roo.bootstrap.HtmlEditorToolbar1
23847 new Roo.bootstrap.HtmlEditor({
23850 new Roo.bootstrap.HtmlEditorToolbar1({
23851 disable : { fonts: 1 , format: 1, ..., ... , ...],
23857 * @cfg {Object} disable List of elements to disable..
23858 * @cfg {Array} btns List of additional buttons.
23862 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23865 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23868 Roo.apply(this, config);
23870 // default disabled, based on 'good practice'..
23871 this.disable = this.disable || {};
23872 Roo.applyIf(this.disable, {
23875 specialElements : true
23877 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23879 this.editor = config.editor;
23880 this.editorcore = config.editor.editorcore;
23882 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23884 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23885 // dont call parent... till later.
23887 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23892 editorcore : false,
23897 "h1","h2","h3","h4","h5","h6",
23899 "abbr", "acronym", "address", "cite", "samp", "var",
23903 onRender : function(ct, position)
23905 // Roo.log("Call onRender: " + this.xtype);
23907 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23909 this.el.dom.style.marginBottom = '0';
23911 var editorcore = this.editorcore;
23912 var editor= this.editor;
23915 var btn = function(id,cmd , toggle, handler, html){
23917 var event = toggle ? 'toggle' : 'click';
23922 xns: Roo.bootstrap,
23925 enableToggle:toggle !== false,
23927 pressed : toggle ? false : null,
23930 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23931 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23937 // var cb_box = function...
23942 xns: Roo.bootstrap,
23943 glyphicon : 'font',
23947 xns: Roo.bootstrap,
23951 Roo.each(this.formats, function(f) {
23952 style.menu.items.push({
23954 xns: Roo.bootstrap,
23955 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23960 editorcore.insertTag(this.tagname);
23967 children.push(style);
23969 btn('bold',false,true);
23970 btn('italic',false,true);
23971 btn('align-left', 'justifyleft',true);
23972 btn('align-center', 'justifycenter',true);
23973 btn('align-right' , 'justifyright',true);
23974 btn('link', false, false, function(btn) {
23975 //Roo.log("create link?");
23976 var url = prompt(this.createLinkText, this.defaultLinkValue);
23977 if(url && url != 'http:/'+'/'){
23978 this.editorcore.relayCmd('createlink', url);
23981 btn('list','insertunorderedlist',true);
23982 btn('pencil', false,true, function(btn){
23984 this.toggleSourceEdit(btn.pressed);
23987 if (this.editor.btns.length > 0) {
23988 for (var i = 0; i<this.editor.btns.length; i++) {
23989 children.push(this.editor.btns[i]);
23997 xns: Roo.bootstrap,
24002 xns: Roo.bootstrap,
24007 cog.menu.items.push({
24009 xns: Roo.bootstrap,
24010 html : Clean styles,
24015 editorcore.insertTag(this.tagname);
24024 this.xtype = 'NavSimplebar';
24026 for(var i=0;i< children.length;i++) {
24028 this.buttons.add(this.addxtypeChild(children[i]));
24032 editor.on('editorevent', this.updateToolbar, this);
24034 onBtnClick : function(id)
24036 this.editorcore.relayCmd(id);
24037 this.editorcore.focus();
24041 * Protected method that will not generally be called directly. It triggers
24042 * a toolbar update by reading the markup state of the current selection in the editor.
24044 updateToolbar: function(){
24046 if(!this.editorcore.activated){
24047 this.editor.onFirstFocus(); // is this neeed?
24051 var btns = this.buttons;
24052 var doc = this.editorcore.doc;
24053 btns.get('bold').setActive(doc.queryCommandState('bold'));
24054 btns.get('italic').setActive(doc.queryCommandState('italic'));
24055 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24057 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24058 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24059 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24061 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24062 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24065 var ans = this.editorcore.getAllAncestors();
24066 if (this.formatCombo) {
24069 var store = this.formatCombo.store;
24070 this.formatCombo.setValue("");
24071 for (var i =0; i < ans.length;i++) {
24072 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24074 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24082 // hides menus... - so this cant be on a menu...
24083 Roo.bootstrap.MenuMgr.hideAll();
24085 Roo.bootstrap.MenuMgr.hideAll();
24086 //this.editorsyncValue();
24088 onFirstFocus: function() {
24089 this.buttons.each(function(item){
24093 toggleSourceEdit : function(sourceEditMode){
24096 if(sourceEditMode){
24097 Roo.log("disabling buttons");
24098 this.buttons.each( function(item){
24099 if(item.cmd != 'pencil'){
24105 Roo.log("enabling buttons");
24106 if(this.editorcore.initialized){
24107 this.buttons.each( function(item){
24113 Roo.log("calling toggole on editor");
24114 // tell the editor that it's been pressed..
24115 this.editor.toggleSourceEdit(sourceEditMode);
24125 * @class Roo.bootstrap.Table.AbstractSelectionModel
24126 * @extends Roo.util.Observable
24127 * Abstract base class for grid SelectionModels. It provides the interface that should be
24128 * implemented by descendant classes. This class should not be directly instantiated.
24131 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24132 this.locked = false;
24133 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24137 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24138 /** @ignore Called by the grid automatically. Do not call directly. */
24139 init : function(grid){
24145 * Locks the selections.
24148 this.locked = true;
24152 * Unlocks the selections.
24154 unlock : function(){
24155 this.locked = false;
24159 * Returns true if the selections are locked.
24160 * @return {Boolean}
24162 isLocked : function(){
24163 return this.locked;
24167 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24168 * @class Roo.bootstrap.Table.RowSelectionModel
24169 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24170 * It supports multiple selections and keyboard selection/navigation.
24172 * @param {Object} config
24175 Roo.bootstrap.Table.RowSelectionModel = function(config){
24176 Roo.apply(this, config);
24177 this.selections = new Roo.util.MixedCollection(false, function(o){
24182 this.lastActive = false;
24186 * @event selectionchange
24187 * Fires when the selection changes
24188 * @param {SelectionModel} this
24190 "selectionchange" : true,
24192 * @event afterselectionchange
24193 * Fires after the selection changes (eg. by key press or clicking)
24194 * @param {SelectionModel} this
24196 "afterselectionchange" : true,
24198 * @event beforerowselect
24199 * Fires when a row is selected being selected, return false to cancel.
24200 * @param {SelectionModel} this
24201 * @param {Number} rowIndex The selected index
24202 * @param {Boolean} keepExisting False if other selections will be cleared
24204 "beforerowselect" : true,
24207 * Fires when a row is selected.
24208 * @param {SelectionModel} this
24209 * @param {Number} rowIndex The selected index
24210 * @param {Roo.data.Record} r The record
24212 "rowselect" : true,
24214 * @event rowdeselect
24215 * Fires when a row is deselected.
24216 * @param {SelectionModel} this
24217 * @param {Number} rowIndex The selected index
24219 "rowdeselect" : true
24221 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24222 this.locked = false;
24225 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24227 * @cfg {Boolean} singleSelect
24228 * True to allow selection of only one row at a time (defaults to false)
24230 singleSelect : false,
24233 initEvents : function()
24236 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24237 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24238 //}else{ // allow click to work like normal
24239 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24241 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24242 this.grid.on("rowclick", this.handleMouseDown, this);
24244 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24245 "up" : function(e){
24247 this.selectPrevious(e.shiftKey);
24248 }else if(this.last !== false && this.lastActive !== false){
24249 var last = this.last;
24250 this.selectRange(this.last, this.lastActive-1);
24251 this.grid.getView().focusRow(this.lastActive);
24252 if(last !== false){
24256 this.selectFirstRow();
24258 this.fireEvent("afterselectionchange", this);
24260 "down" : function(e){
24262 this.selectNext(e.shiftKey);
24263 }else if(this.last !== false && this.lastActive !== false){
24264 var last = this.last;
24265 this.selectRange(this.last, this.lastActive+1);
24266 this.grid.getView().focusRow(this.lastActive);
24267 if(last !== false){
24271 this.selectFirstRow();
24273 this.fireEvent("afterselectionchange", this);
24277 this.grid.store.on('load', function(){
24278 this.selections.clear();
24281 var view = this.grid.view;
24282 view.on("refresh", this.onRefresh, this);
24283 view.on("rowupdated", this.onRowUpdated, this);
24284 view.on("rowremoved", this.onRemove, this);
24289 onRefresh : function()
24291 var ds = this.grid.store, i, v = this.grid.view;
24292 var s = this.selections;
24293 s.each(function(r){
24294 if((i = ds.indexOfId(r.id)) != -1){
24303 onRemove : function(v, index, r){
24304 this.selections.remove(r);
24308 onRowUpdated : function(v, index, r){
24309 if(this.isSelected(r)){
24310 v.onRowSelect(index);
24316 * @param {Array} records The records to select
24317 * @param {Boolean} keepExisting (optional) True to keep existing selections
24319 selectRecords : function(records, keepExisting)
24322 this.clearSelections();
24324 var ds = this.grid.store;
24325 for(var i = 0, len = records.length; i < len; i++){
24326 this.selectRow(ds.indexOf(records[i]), true);
24331 * Gets the number of selected rows.
24334 getCount : function(){
24335 return this.selections.length;
24339 * Selects the first row in the grid.
24341 selectFirstRow : function(){
24346 * Select the last row.
24347 * @param {Boolean} keepExisting (optional) True to keep existing selections
24349 selectLastRow : function(keepExisting){
24350 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24351 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24355 * Selects the row immediately following the last selected row.
24356 * @param {Boolean} keepExisting (optional) True to keep existing selections
24358 selectNext : function(keepExisting)
24360 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24361 this.selectRow(this.last+1, keepExisting);
24362 this.grid.getView().focusRow(this.last);
24367 * Selects the row that precedes the last selected row.
24368 * @param {Boolean} keepExisting (optional) True to keep existing selections
24370 selectPrevious : function(keepExisting){
24372 this.selectRow(this.last-1, keepExisting);
24373 this.grid.getView().focusRow(this.last);
24378 * Returns the selected records
24379 * @return {Array} Array of selected records
24381 getSelections : function(){
24382 return [].concat(this.selections.items);
24386 * Returns the first selected record.
24389 getSelected : function(){
24390 return this.selections.itemAt(0);
24395 * Clears all selections.
24397 clearSelections : function(fast)
24403 var ds = this.grid.store;
24404 var s = this.selections;
24405 s.each(function(r){
24406 this.deselectRow(ds.indexOfId(r.id));
24410 this.selections.clear();
24417 * Selects all rows.
24419 selectAll : function(){
24423 this.selections.clear();
24424 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24425 this.selectRow(i, true);
24430 * Returns True if there is a selection.
24431 * @return {Boolean}
24433 hasSelection : function(){
24434 return this.selections.length > 0;
24438 * Returns True if the specified row is selected.
24439 * @param {Number/Record} record The record or index of the record to check
24440 * @return {Boolean}
24442 isSelected : function(index){
24443 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24444 return (r && this.selections.key(r.id) ? true : false);
24448 * Returns True if the specified record id is selected.
24449 * @param {String} id The id of record to check
24450 * @return {Boolean}
24452 isIdSelected : function(id){
24453 return (this.selections.key(id) ? true : false);
24458 handleMouseDBClick : function(e, t){
24462 handleMouseDown : function(e, t)
24464 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24465 if(this.isLocked() || rowIndex < 0 ){
24468 if(e.shiftKey && this.last !== false){
24469 var last = this.last;
24470 this.selectRange(last, rowIndex, e.ctrlKey);
24471 this.last = last; // reset the last
24475 var isSelected = this.isSelected(rowIndex);
24476 //Roo.log("select row:" + rowIndex);
24478 this.deselectRow(rowIndex);
24480 this.selectRow(rowIndex, true);
24484 if(e.button !== 0 && isSelected){
24485 alert('rowIndex 2: ' + rowIndex);
24486 view.focusRow(rowIndex);
24487 }else if(e.ctrlKey && isSelected){
24488 this.deselectRow(rowIndex);
24489 }else if(!isSelected){
24490 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24491 view.focusRow(rowIndex);
24495 this.fireEvent("afterselectionchange", this);
24498 handleDragableRowClick : function(grid, rowIndex, e)
24500 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24501 this.selectRow(rowIndex, false);
24502 grid.view.focusRow(rowIndex);
24503 this.fireEvent("afterselectionchange", this);
24508 * Selects multiple rows.
24509 * @param {Array} rows Array of the indexes of the row to select
24510 * @param {Boolean} keepExisting (optional) True to keep existing selections
24512 selectRows : function(rows, keepExisting){
24514 this.clearSelections();
24516 for(var i = 0, len = rows.length; i < len; i++){
24517 this.selectRow(rows[i], true);
24522 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24523 * @param {Number} startRow The index of the first row in the range
24524 * @param {Number} endRow The index of the last row in the range
24525 * @param {Boolean} keepExisting (optional) True to retain existing selections
24527 selectRange : function(startRow, endRow, keepExisting){
24532 this.clearSelections();
24534 if(startRow <= endRow){
24535 for(var i = startRow; i <= endRow; i++){
24536 this.selectRow(i, true);
24539 for(var i = startRow; i >= endRow; i--){
24540 this.selectRow(i, true);
24546 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24547 * @param {Number} startRow The index of the first row in the range
24548 * @param {Number} endRow The index of the last row in the range
24550 deselectRange : function(startRow, endRow, preventViewNotify){
24554 for(var i = startRow; i <= endRow; i++){
24555 this.deselectRow(i, preventViewNotify);
24561 * @param {Number} row The index of the row to select
24562 * @param {Boolean} keepExisting (optional) True to keep existing selections
24564 selectRow : function(index, keepExisting, preventViewNotify)
24566 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24569 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24570 if(!keepExisting || this.singleSelect){
24571 this.clearSelections();
24574 var r = this.grid.store.getAt(index);
24575 //console.log('selectRow - record id :' + r.id);
24577 this.selections.add(r);
24578 this.last = this.lastActive = index;
24579 if(!preventViewNotify){
24580 var proxy = new Roo.Element(
24581 this.grid.getRowDom(index)
24583 proxy.addClass('bg-info info');
24585 this.fireEvent("rowselect", this, index, r);
24586 this.fireEvent("selectionchange", this);
24592 * @param {Number} row The index of the row to deselect
24594 deselectRow : function(index, preventViewNotify)
24599 if(this.last == index){
24602 if(this.lastActive == index){
24603 this.lastActive = false;
24606 var r = this.grid.store.getAt(index);
24611 this.selections.remove(r);
24612 //.console.log('deselectRow - record id :' + r.id);
24613 if(!preventViewNotify){
24615 var proxy = new Roo.Element(
24616 this.grid.getRowDom(index)
24618 proxy.removeClass('bg-info info');
24620 this.fireEvent("rowdeselect", this, index);
24621 this.fireEvent("selectionchange", this);
24625 restoreLast : function(){
24627 this.last = this._last;
24632 acceptsNav : function(row, col, cm){
24633 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24637 onEditorKey : function(field, e){
24638 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24643 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24645 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24647 }else if(k == e.ENTER && !e.ctrlKey){
24651 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24653 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24655 }else if(k == e.ESC){
24659 g.startEditing(newCell[0], newCell[1]);
24665 * Ext JS Library 1.1.1
24666 * Copyright(c) 2006-2007, Ext JS, LLC.
24668 * Originally Released Under LGPL - original licence link has changed is not relivant.
24671 * <script type="text/javascript">
24675 * @class Roo.bootstrap.PagingToolbar
24676 * @extends Roo.bootstrap.NavSimplebar
24677 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24679 * Create a new PagingToolbar
24680 * @param {Object} config The config object
24681 * @param {Roo.data.Store} store
24683 Roo.bootstrap.PagingToolbar = function(config)
24685 // old args format still supported... - xtype is prefered..
24686 // created from xtype...
24688 this.ds = config.dataSource;
24690 if (config.store && !this.ds) {
24691 this.store= Roo.factory(config.store, Roo.data);
24692 this.ds = this.store;
24693 this.ds.xmodule = this.xmodule || false;
24696 this.toolbarItems = [];
24697 if (config.items) {
24698 this.toolbarItems = config.items;
24701 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24706 this.bind(this.ds);
24709 if (Roo.bootstrap.version == 4) {
24710 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24712 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24717 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24719 * @cfg {Roo.data.Store} dataSource
24720 * The underlying data store providing the paged data
24723 * @cfg {String/HTMLElement/Element} container
24724 * container The id or element that will contain the toolbar
24727 * @cfg {Boolean} displayInfo
24728 * True to display the displayMsg (defaults to false)
24731 * @cfg {Number} pageSize
24732 * The number of records to display per page (defaults to 20)
24736 * @cfg {String} displayMsg
24737 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24739 displayMsg : 'Displaying {0} - {1} of {2}',
24741 * @cfg {String} emptyMsg
24742 * The message to display when no records are found (defaults to "No data to display")
24744 emptyMsg : 'No data to display',
24746 * Customizable piece of the default paging text (defaults to "Page")
24749 beforePageText : "Page",
24751 * Customizable piece of the default paging text (defaults to "of %0")
24754 afterPageText : "of {0}",
24756 * Customizable piece of the default paging text (defaults to "First Page")
24759 firstText : "First Page",
24761 * Customizable piece of the default paging text (defaults to "Previous Page")
24764 prevText : "Previous Page",
24766 * Customizable piece of the default paging text (defaults to "Next Page")
24769 nextText : "Next Page",
24771 * Customizable piece of the default paging text (defaults to "Last Page")
24774 lastText : "Last Page",
24776 * Customizable piece of the default paging text (defaults to "Refresh")
24779 refreshText : "Refresh",
24783 onRender : function(ct, position)
24785 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24786 this.navgroup.parentId = this.id;
24787 this.navgroup.onRender(this.el, null);
24788 // add the buttons to the navgroup
24790 if(this.displayInfo){
24791 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24792 this.displayEl = this.el.select('.x-paging-info', true).first();
24793 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24794 // this.displayEl = navel.el.select('span',true).first();
24800 Roo.each(_this.buttons, function(e){ // this might need to use render????
24801 Roo.factory(e).render(_this.el);
24805 Roo.each(_this.toolbarItems, function(e) {
24806 _this.navgroup.addItem(e);
24810 this.first = this.navgroup.addItem({
24811 tooltip: this.firstText,
24812 cls: "prev btn-outline-secondary",
24813 html : ' <i class="fa fa-step-backward"></i>',
24815 preventDefault: true,
24816 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24819 this.prev = this.navgroup.addItem({
24820 tooltip: this.prevText,
24821 cls: "prev btn-outline-secondary",
24822 html : ' <i class="fa fa-backward"></i>',
24824 preventDefault: true,
24825 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24827 //this.addSeparator();
24830 var field = this.navgroup.addItem( {
24832 cls : 'x-paging-position btn-outline-secondary',
24834 html : this.beforePageText +
24835 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24836 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24839 this.field = field.el.select('input', true).first();
24840 this.field.on("keydown", this.onPagingKeydown, this);
24841 this.field.on("focus", function(){this.dom.select();});
24844 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24845 //this.field.setHeight(18);
24846 //this.addSeparator();
24847 this.next = this.navgroup.addItem({
24848 tooltip: this.nextText,
24849 cls: "next btn-outline-secondary",
24850 html : ' <i class="fa fa-forward"></i>',
24852 preventDefault: true,
24853 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24855 this.last = this.navgroup.addItem({
24856 tooltip: this.lastText,
24857 html : ' <i class="fa fa-step-forward"></i>',
24858 cls: "next btn-outline-secondary",
24860 preventDefault: true,
24861 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24863 //this.addSeparator();
24864 this.loading = this.navgroup.addItem({
24865 tooltip: this.refreshText,
24866 cls: "btn-outline-secondary",
24867 html : ' <i class="fa fa-refresh"></i>',
24868 preventDefault: true,
24869 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24875 updateInfo : function(){
24876 if(this.displayEl){
24877 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24878 var msg = count == 0 ?
24882 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24884 this.displayEl.update(msg);
24889 onLoad : function(ds, r, o)
24891 this.cursor = o.params.start ? o.params.start : 0;
24893 var d = this.getPageData(),
24898 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24899 this.field.dom.value = ap;
24900 this.first.setDisabled(ap == 1);
24901 this.prev.setDisabled(ap == 1);
24902 this.next.setDisabled(ap == ps);
24903 this.last.setDisabled(ap == ps);
24904 this.loading.enable();
24909 getPageData : function(){
24910 var total = this.ds.getTotalCount();
24913 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24914 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24919 onLoadError : function(){
24920 this.loading.enable();
24924 onPagingKeydown : function(e){
24925 var k = e.getKey();
24926 var d = this.getPageData();
24928 var v = this.field.dom.value, pageNum;
24929 if(!v || isNaN(pageNum = parseInt(v, 10))){
24930 this.field.dom.value = d.activePage;
24933 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24934 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24937 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))
24939 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24940 this.field.dom.value = pageNum;
24941 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24944 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24946 var v = this.field.dom.value, pageNum;
24947 var increment = (e.shiftKey) ? 10 : 1;
24948 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24951 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24952 this.field.dom.value = d.activePage;
24955 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24957 this.field.dom.value = parseInt(v, 10) + increment;
24958 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24959 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24966 beforeLoad : function(){
24968 this.loading.disable();
24973 onClick : function(which){
24982 ds.load({params:{start: 0, limit: this.pageSize}});
24985 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24988 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24991 var total = ds.getTotalCount();
24992 var extra = total % this.pageSize;
24993 var lastStart = extra ? (total - extra) : total-this.pageSize;
24994 ds.load({params:{start: lastStart, limit: this.pageSize}});
24997 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25003 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25004 * @param {Roo.data.Store} store The data store to unbind
25006 unbind : function(ds){
25007 ds.un("beforeload", this.beforeLoad, this);
25008 ds.un("load", this.onLoad, this);
25009 ds.un("loadexception", this.onLoadError, this);
25010 ds.un("remove", this.updateInfo, this);
25011 ds.un("add", this.updateInfo, this);
25012 this.ds = undefined;
25016 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25017 * @param {Roo.data.Store} store The data store to bind
25019 bind : function(ds){
25020 ds.on("beforeload", this.beforeLoad, this);
25021 ds.on("load", this.onLoad, this);
25022 ds.on("loadexception", this.onLoadError, this);
25023 ds.on("remove", this.updateInfo, this);
25024 ds.on("add", this.updateInfo, this);
25035 * @class Roo.bootstrap.MessageBar
25036 * @extends Roo.bootstrap.Component
25037 * Bootstrap MessageBar class
25038 * @cfg {String} html contents of the MessageBar
25039 * @cfg {String} weight (info | success | warning | danger) default info
25040 * @cfg {String} beforeClass insert the bar before the given class
25041 * @cfg {Boolean} closable (true | false) default false
25042 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25045 * Create a new Element
25046 * @param {Object} config The config object
25049 Roo.bootstrap.MessageBar = function(config){
25050 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25053 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25059 beforeClass: 'bootstrap-sticky-wrap',
25061 getAutoCreate : function(){
25065 cls: 'alert alert-dismissable alert-' + this.weight,
25070 html: this.html || ''
25076 cfg.cls += ' alert-messages-fixed';
25090 onRender : function(ct, position)
25092 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25095 var cfg = Roo.apply({}, this.getAutoCreate());
25099 cfg.cls += ' ' + this.cls;
25102 cfg.style = this.style;
25104 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25106 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25109 this.el.select('>button.close').on('click', this.hide, this);
25115 if (!this.rendered) {
25121 this.fireEvent('show', this);
25127 if (!this.rendered) {
25133 this.fireEvent('hide', this);
25136 update : function()
25138 // var e = this.el.dom.firstChild;
25140 // if(this.closable){
25141 // e = e.nextSibling;
25144 // e.data = this.html || '';
25146 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25162 * @class Roo.bootstrap.Graph
25163 * @extends Roo.bootstrap.Component
25164 * Bootstrap Graph class
25168 @cfg {String} graphtype bar | vbar | pie
25169 @cfg {number} g_x coodinator | centre x (pie)
25170 @cfg {number} g_y coodinator | centre y (pie)
25171 @cfg {number} g_r radius (pie)
25172 @cfg {number} g_height height of the chart (respected by all elements in the set)
25173 @cfg {number} g_width width of the chart (respected by all elements in the set)
25174 @cfg {Object} title The title of the chart
25177 -opts (object) options for the chart
25179 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25180 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25182 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.
25183 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25185 o stretch (boolean)
25187 -opts (object) options for the pie
25190 o startAngle (number)
25191 o endAngle (number)
25195 * Create a new Input
25196 * @param {Object} config The config object
25199 Roo.bootstrap.Graph = function(config){
25200 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25206 * The img click event for the img.
25207 * @param {Roo.EventObject} e
25213 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25224 //g_colors: this.colors,
25231 getAutoCreate : function(){
25242 onRender : function(ct,position){
25245 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25247 if (typeof(Raphael) == 'undefined') {
25248 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25252 this.raphael = Raphael(this.el.dom);
25254 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25255 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25256 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25257 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25259 r.text(160, 10, "Single Series Chart").attr(txtattr);
25260 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25261 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25262 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25264 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25265 r.barchart(330, 10, 300, 220, data1);
25266 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25267 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25270 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25271 // r.barchart(30, 30, 560, 250, xdata, {
25272 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25273 // axis : "0 0 1 1",
25274 // axisxlabels : xdata
25275 // //yvalues : cols,
25278 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25280 // this.load(null,xdata,{
25281 // axis : "0 0 1 1",
25282 // axisxlabels : xdata
25287 load : function(graphtype,xdata,opts)
25289 this.raphael.clear();
25291 graphtype = this.graphtype;
25296 var r = this.raphael,
25297 fin = function () {
25298 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25300 fout = function () {
25301 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25303 pfin = function() {
25304 this.sector.stop();
25305 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25308 this.label[0].stop();
25309 this.label[0].attr({ r: 7.5 });
25310 this.label[1].attr({ "font-weight": 800 });
25313 pfout = function() {
25314 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25317 this.label[0].animate({ r: 5 }, 500, "bounce");
25318 this.label[1].attr({ "font-weight": 400 });
25324 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25327 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25330 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25331 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25333 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25340 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25345 setTitle: function(o)
25350 initEvents: function() {
25353 this.el.on('click', this.onClick, this);
25357 onClick : function(e)
25359 Roo.log('img onclick');
25360 this.fireEvent('click', this, e);
25372 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25375 * @class Roo.bootstrap.dash.NumberBox
25376 * @extends Roo.bootstrap.Component
25377 * Bootstrap NumberBox class
25378 * @cfg {String} headline Box headline
25379 * @cfg {String} content Box content
25380 * @cfg {String} icon Box icon
25381 * @cfg {String} footer Footer text
25382 * @cfg {String} fhref Footer href
25385 * Create a new NumberBox
25386 * @param {Object} config The config object
25390 Roo.bootstrap.dash.NumberBox = function(config){
25391 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25395 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25404 getAutoCreate : function(){
25408 cls : 'small-box ',
25416 cls : 'roo-headline',
25417 html : this.headline
25421 cls : 'roo-content',
25422 html : this.content
25436 cls : 'ion ' + this.icon
25445 cls : 'small-box-footer',
25446 href : this.fhref || '#',
25450 cfg.cn.push(footer);
25457 onRender : function(ct,position){
25458 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25465 setHeadline: function (value)
25467 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25470 setFooter: function (value, href)
25472 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25475 this.el.select('a.small-box-footer',true).first().attr('href', href);
25480 setContent: function (value)
25482 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25485 initEvents: function()
25499 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25502 * @class Roo.bootstrap.dash.TabBox
25503 * @extends Roo.bootstrap.Component
25504 * Bootstrap TabBox class
25505 * @cfg {String} title Title of the TabBox
25506 * @cfg {String} icon Icon of the TabBox
25507 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25508 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25511 * Create a new TabBox
25512 * @param {Object} config The config object
25516 Roo.bootstrap.dash.TabBox = function(config){
25517 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25522 * When a pane is added
25523 * @param {Roo.bootstrap.dash.TabPane} pane
25527 * @event activatepane
25528 * When a pane is activated
25529 * @param {Roo.bootstrap.dash.TabPane} pane
25531 "activatepane" : true
25539 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25544 tabScrollable : false,
25546 getChildContainer : function()
25548 return this.el.select('.tab-content', true).first();
25551 getAutoCreate : function(){
25555 cls: 'pull-left header',
25563 cls: 'fa ' + this.icon
25569 cls: 'nav nav-tabs pull-right',
25575 if(this.tabScrollable){
25582 cls: 'nav nav-tabs pull-right',
25593 cls: 'nav-tabs-custom',
25598 cls: 'tab-content no-padding',
25606 initEvents : function()
25608 //Roo.log('add add pane handler');
25609 this.on('addpane', this.onAddPane, this);
25612 * Updates the box title
25613 * @param {String} html to set the title to.
25615 setTitle : function(value)
25617 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25619 onAddPane : function(pane)
25621 this.panes.push(pane);
25622 //Roo.log('addpane');
25624 // tabs are rendere left to right..
25625 if(!this.showtabs){
25629 var ctr = this.el.select('.nav-tabs', true).first();
25632 var existing = ctr.select('.nav-tab',true);
25633 var qty = existing.getCount();;
25636 var tab = ctr.createChild({
25638 cls : 'nav-tab' + (qty ? '' : ' active'),
25646 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25649 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25651 pane.el.addClass('active');
25656 onTabClick : function(ev,un,ob,pane)
25658 //Roo.log('tab - prev default');
25659 ev.preventDefault();
25662 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25663 pane.tab.addClass('active');
25664 //Roo.log(pane.title);
25665 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25666 // technically we should have a deactivate event.. but maybe add later.
25667 // and it should not de-activate the selected tab...
25668 this.fireEvent('activatepane', pane);
25669 pane.el.addClass('active');
25670 pane.fireEvent('activate');
25675 getActivePane : function()
25678 Roo.each(this.panes, function(p) {
25679 if(p.el.hasClass('active')){
25700 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25702 * @class Roo.bootstrap.TabPane
25703 * @extends Roo.bootstrap.Component
25704 * Bootstrap TabPane class
25705 * @cfg {Boolean} active (false | true) Default false
25706 * @cfg {String} title title of panel
25710 * Create a new TabPane
25711 * @param {Object} config The config object
25714 Roo.bootstrap.dash.TabPane = function(config){
25715 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25721 * When a pane is activated
25722 * @param {Roo.bootstrap.dash.TabPane} pane
25729 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25734 // the tabBox that this is attached to.
25737 getAutoCreate : function()
25745 cfg.cls += ' active';
25750 initEvents : function()
25752 //Roo.log('trigger add pane handler');
25753 this.parent().fireEvent('addpane', this)
25757 * Updates the tab title
25758 * @param {String} html to set the title to.
25760 setTitle: function(str)
25766 this.tab.select('a', true).first().dom.innerHTML = str;
25783 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25786 * @class Roo.bootstrap.menu.Menu
25787 * @extends Roo.bootstrap.Component
25788 * Bootstrap Menu class - container for Menu
25789 * @cfg {String} html Text of the menu
25790 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25791 * @cfg {String} icon Font awesome icon
25792 * @cfg {String} pos Menu align to (top | bottom) default bottom
25796 * Create a new Menu
25797 * @param {Object} config The config object
25801 Roo.bootstrap.menu.Menu = function(config){
25802 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25806 * @event beforeshow
25807 * Fires before this menu is displayed
25808 * @param {Roo.bootstrap.menu.Menu} this
25812 * @event beforehide
25813 * Fires before this menu is hidden
25814 * @param {Roo.bootstrap.menu.Menu} this
25819 * Fires after this menu is displayed
25820 * @param {Roo.bootstrap.menu.Menu} this
25825 * Fires after this menu is hidden
25826 * @param {Roo.bootstrap.menu.Menu} this
25831 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25832 * @param {Roo.bootstrap.menu.Menu} this
25833 * @param {Roo.EventObject} e
25840 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25844 weight : 'default',
25849 getChildContainer : function() {
25850 if(this.isSubMenu){
25854 return this.el.select('ul.dropdown-menu', true).first();
25857 getAutoCreate : function()
25862 cls : 'roo-menu-text',
25870 cls : 'fa ' + this.icon
25881 cls : 'dropdown-button btn btn-' + this.weight,
25886 cls : 'dropdown-toggle btn btn-' + this.weight,
25896 cls : 'dropdown-menu'
25902 if(this.pos == 'top'){
25903 cfg.cls += ' dropup';
25906 if(this.isSubMenu){
25909 cls : 'dropdown-menu'
25916 onRender : function(ct, position)
25918 this.isSubMenu = ct.hasClass('dropdown-submenu');
25920 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25923 initEvents : function()
25925 if(this.isSubMenu){
25929 this.hidden = true;
25931 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25932 this.triggerEl.on('click', this.onTriggerPress, this);
25934 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25935 this.buttonEl.on('click', this.onClick, this);
25941 if(this.isSubMenu){
25945 return this.el.select('ul.dropdown-menu', true).first();
25948 onClick : function(e)
25950 this.fireEvent("click", this, e);
25953 onTriggerPress : function(e)
25955 if (this.isVisible()) {
25962 isVisible : function(){
25963 return !this.hidden;
25968 this.fireEvent("beforeshow", this);
25970 this.hidden = false;
25971 this.el.addClass('open');
25973 Roo.get(document).on("mouseup", this.onMouseUp, this);
25975 this.fireEvent("show", this);
25982 this.fireEvent("beforehide", this);
25984 this.hidden = true;
25985 this.el.removeClass('open');
25987 Roo.get(document).un("mouseup", this.onMouseUp);
25989 this.fireEvent("hide", this);
25992 onMouseUp : function()
26006 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26009 * @class Roo.bootstrap.menu.Item
26010 * @extends Roo.bootstrap.Component
26011 * Bootstrap MenuItem class
26012 * @cfg {Boolean} submenu (true | false) default false
26013 * @cfg {String} html text of the item
26014 * @cfg {String} href the link
26015 * @cfg {Boolean} disable (true | false) default false
26016 * @cfg {Boolean} preventDefault (true | false) default true
26017 * @cfg {String} icon Font awesome icon
26018 * @cfg {String} pos Submenu align to (left | right) default right
26022 * Create a new Item
26023 * @param {Object} config The config object
26027 Roo.bootstrap.menu.Item = function(config){
26028 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26032 * Fires when the mouse is hovering over this menu
26033 * @param {Roo.bootstrap.menu.Item} this
26034 * @param {Roo.EventObject} e
26039 * Fires when the mouse exits this menu
26040 * @param {Roo.bootstrap.menu.Item} this
26041 * @param {Roo.EventObject} e
26047 * The raw click event for the entire grid.
26048 * @param {Roo.EventObject} e
26054 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26059 preventDefault: true,
26064 getAutoCreate : function()
26069 cls : 'roo-menu-item-text',
26077 cls : 'fa ' + this.icon
26086 href : this.href || '#',
26093 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26097 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26099 if(this.pos == 'left'){
26100 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26107 initEvents : function()
26109 this.el.on('mouseover', this.onMouseOver, this);
26110 this.el.on('mouseout', this.onMouseOut, this);
26112 this.el.select('a', true).first().on('click', this.onClick, this);
26116 onClick : function(e)
26118 if(this.preventDefault){
26119 e.preventDefault();
26122 this.fireEvent("click", this, e);
26125 onMouseOver : function(e)
26127 if(this.submenu && this.pos == 'left'){
26128 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26131 this.fireEvent("mouseover", this, e);
26134 onMouseOut : function(e)
26136 this.fireEvent("mouseout", this, e);
26148 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26151 * @class Roo.bootstrap.menu.Separator
26152 * @extends Roo.bootstrap.Component
26153 * Bootstrap Separator class
26156 * Create a new Separator
26157 * @param {Object} config The config object
26161 Roo.bootstrap.menu.Separator = function(config){
26162 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26165 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26167 getAutoCreate : function(){
26188 * @class Roo.bootstrap.Tooltip
26189 * Bootstrap Tooltip class
26190 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26191 * to determine which dom element triggers the tooltip.
26193 * It needs to add support for additional attributes like tooltip-position
26196 * Create a new Toolti
26197 * @param {Object} config The config object
26200 Roo.bootstrap.Tooltip = function(config){
26201 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26203 this.alignment = Roo.bootstrap.Tooltip.alignment;
26205 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26206 this.alignment = config.alignment;
26211 Roo.apply(Roo.bootstrap.Tooltip, {
26213 * @function init initialize tooltip monitoring.
26217 currentTip : false,
26218 currentRegion : false,
26224 Roo.get(document).on('mouseover', this.enter ,this);
26225 Roo.get(document).on('mouseout', this.leave, this);
26228 this.currentTip = new Roo.bootstrap.Tooltip();
26231 enter : function(ev)
26233 var dom = ev.getTarget();
26235 //Roo.log(['enter',dom]);
26236 var el = Roo.fly(dom);
26237 if (this.currentEl) {
26239 //Roo.log(this.currentEl);
26240 //Roo.log(this.currentEl.contains(dom));
26241 if (this.currentEl == el) {
26244 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26250 if (this.currentTip.el) {
26251 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26255 if(!el || el.dom == document){
26261 // you can not look for children, as if el is the body.. then everythign is the child..
26262 if (!el.attr('tooltip')) { //
26263 if (!el.select("[tooltip]").elements.length) {
26266 // is the mouse over this child...?
26267 bindEl = el.select("[tooltip]").first();
26268 var xy = ev.getXY();
26269 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26270 //Roo.log("not in region.");
26273 //Roo.log("child element over..");
26276 this.currentEl = bindEl;
26277 this.currentTip.bind(bindEl);
26278 this.currentRegion = Roo.lib.Region.getRegion(dom);
26279 this.currentTip.enter();
26282 leave : function(ev)
26284 var dom = ev.getTarget();
26285 //Roo.log(['leave',dom]);
26286 if (!this.currentEl) {
26291 if (dom != this.currentEl.dom) {
26294 var xy = ev.getXY();
26295 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26298 // only activate leave if mouse cursor is outside... bounding box..
26303 if (this.currentTip) {
26304 this.currentTip.leave();
26306 //Roo.log('clear currentEl');
26307 this.currentEl = false;
26312 'left' : ['r-l', [-2,0], 'right'],
26313 'right' : ['l-r', [2,0], 'left'],
26314 'bottom' : ['t-b', [0,2], 'top'],
26315 'top' : [ 'b-t', [0,-2], 'bottom']
26321 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26326 delay : null, // can be { show : 300 , hide: 500}
26330 hoverState : null, //???
26332 placement : 'bottom',
26336 getAutoCreate : function(){
26343 cls : 'tooltip-arrow'
26346 cls : 'tooltip-inner'
26353 bind : function(el)
26359 enter : function () {
26361 if (this.timeout != null) {
26362 clearTimeout(this.timeout);
26365 this.hoverState = 'in';
26366 //Roo.log("enter - show");
26367 if (!this.delay || !this.delay.show) {
26372 this.timeout = setTimeout(function () {
26373 if (_t.hoverState == 'in') {
26376 }, this.delay.show);
26380 clearTimeout(this.timeout);
26382 this.hoverState = 'out';
26383 if (!this.delay || !this.delay.hide) {
26389 this.timeout = setTimeout(function () {
26390 //Roo.log("leave - timeout");
26392 if (_t.hoverState == 'out') {
26394 Roo.bootstrap.Tooltip.currentEl = false;
26399 show : function (msg)
26402 this.render(document.body);
26405 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26407 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26409 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26411 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26413 var placement = typeof this.placement == 'function' ?
26414 this.placement.call(this, this.el, on_el) :
26417 var autoToken = /\s?auto?\s?/i;
26418 var autoPlace = autoToken.test(placement);
26420 placement = placement.replace(autoToken, '') || 'top';
26424 //this.el.setXY([0,0]);
26426 //this.el.dom.style.display='block';
26428 //this.el.appendTo(on_el);
26430 var p = this.getPosition();
26431 var box = this.el.getBox();
26437 var align = this.alignment[placement];
26439 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26441 if(placement == 'top' || placement == 'bottom'){
26443 placement = 'right';
26446 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26447 placement = 'left';
26450 var scroll = Roo.select('body', true).first().getScroll();
26452 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26456 align = this.alignment[placement];
26459 this.el.alignTo(this.bindEl, align[0],align[1]);
26460 //var arrow = this.el.select('.arrow',true).first();
26461 //arrow.set(align[2],
26463 this.el.addClass(placement);
26465 this.el.addClass('in fade');
26467 this.hoverState = null;
26469 if (this.el.hasClass('fade')) {
26480 //this.el.setXY([0,0]);
26481 this.el.removeClass('in');
26497 * @class Roo.bootstrap.LocationPicker
26498 * @extends Roo.bootstrap.Component
26499 * Bootstrap LocationPicker class
26500 * @cfg {Number} latitude Position when init default 0
26501 * @cfg {Number} longitude Position when init default 0
26502 * @cfg {Number} zoom default 15
26503 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26504 * @cfg {Boolean} mapTypeControl default false
26505 * @cfg {Boolean} disableDoubleClickZoom default false
26506 * @cfg {Boolean} scrollwheel default true
26507 * @cfg {Boolean} streetViewControl default false
26508 * @cfg {Number} radius default 0
26509 * @cfg {String} locationName
26510 * @cfg {Boolean} draggable default true
26511 * @cfg {Boolean} enableAutocomplete default false
26512 * @cfg {Boolean} enableReverseGeocode default true
26513 * @cfg {String} markerTitle
26516 * Create a new LocationPicker
26517 * @param {Object} config The config object
26521 Roo.bootstrap.LocationPicker = function(config){
26523 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26528 * Fires when the picker initialized.
26529 * @param {Roo.bootstrap.LocationPicker} this
26530 * @param {Google Location} location
26534 * @event positionchanged
26535 * Fires when the picker position changed.
26536 * @param {Roo.bootstrap.LocationPicker} this
26537 * @param {Google Location} location
26539 positionchanged : true,
26542 * Fires when the map resize.
26543 * @param {Roo.bootstrap.LocationPicker} this
26548 * Fires when the map show.
26549 * @param {Roo.bootstrap.LocationPicker} this
26554 * Fires when the map hide.
26555 * @param {Roo.bootstrap.LocationPicker} this
26560 * Fires when click the map.
26561 * @param {Roo.bootstrap.LocationPicker} this
26562 * @param {Map event} e
26566 * @event mapRightClick
26567 * Fires when right click the map.
26568 * @param {Roo.bootstrap.LocationPicker} this
26569 * @param {Map event} e
26571 mapRightClick : true,
26573 * @event markerClick
26574 * Fires when click the marker.
26575 * @param {Roo.bootstrap.LocationPicker} this
26576 * @param {Map event} e
26578 markerClick : true,
26580 * @event markerRightClick
26581 * Fires when right click the marker.
26582 * @param {Roo.bootstrap.LocationPicker} this
26583 * @param {Map event} e
26585 markerRightClick : true,
26587 * @event OverlayViewDraw
26588 * Fires when OverlayView Draw
26589 * @param {Roo.bootstrap.LocationPicker} this
26591 OverlayViewDraw : true,
26593 * @event OverlayViewOnAdd
26594 * Fires when OverlayView Draw
26595 * @param {Roo.bootstrap.LocationPicker} this
26597 OverlayViewOnAdd : true,
26599 * @event OverlayViewOnRemove
26600 * Fires when OverlayView Draw
26601 * @param {Roo.bootstrap.LocationPicker} this
26603 OverlayViewOnRemove : true,
26605 * @event OverlayViewShow
26606 * Fires when OverlayView Draw
26607 * @param {Roo.bootstrap.LocationPicker} this
26608 * @param {Pixel} cpx
26610 OverlayViewShow : true,
26612 * @event OverlayViewHide
26613 * Fires when OverlayView Draw
26614 * @param {Roo.bootstrap.LocationPicker} this
26616 OverlayViewHide : true,
26618 * @event loadexception
26619 * Fires when load google lib failed.
26620 * @param {Roo.bootstrap.LocationPicker} this
26622 loadexception : true
26627 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26629 gMapContext: false,
26635 mapTypeControl: false,
26636 disableDoubleClickZoom: false,
26638 streetViewControl: false,
26642 enableAutocomplete: false,
26643 enableReverseGeocode: true,
26646 getAutoCreate: function()
26651 cls: 'roo-location-picker'
26657 initEvents: function(ct, position)
26659 if(!this.el.getWidth() || this.isApplied()){
26663 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26668 initial: function()
26670 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26671 this.fireEvent('loadexception', this);
26675 if(!this.mapTypeId){
26676 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26679 this.gMapContext = this.GMapContext();
26681 this.initOverlayView();
26683 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26687 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26688 _this.setPosition(_this.gMapContext.marker.position);
26691 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26692 _this.fireEvent('mapClick', this, event);
26696 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26697 _this.fireEvent('mapRightClick', this, event);
26701 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26702 _this.fireEvent('markerClick', this, event);
26706 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26707 _this.fireEvent('markerRightClick', this, event);
26711 this.setPosition(this.gMapContext.location);
26713 this.fireEvent('initial', this, this.gMapContext.location);
26716 initOverlayView: function()
26720 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26724 _this.fireEvent('OverlayViewDraw', _this);
26729 _this.fireEvent('OverlayViewOnAdd', _this);
26732 onRemove: function()
26734 _this.fireEvent('OverlayViewOnRemove', _this);
26737 show: function(cpx)
26739 _this.fireEvent('OverlayViewShow', _this, cpx);
26744 _this.fireEvent('OverlayViewHide', _this);
26750 fromLatLngToContainerPixel: function(event)
26752 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26755 isApplied: function()
26757 return this.getGmapContext() == false ? false : true;
26760 getGmapContext: function()
26762 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26765 GMapContext: function()
26767 var position = new google.maps.LatLng(this.latitude, this.longitude);
26769 var _map = new google.maps.Map(this.el.dom, {
26772 mapTypeId: this.mapTypeId,
26773 mapTypeControl: this.mapTypeControl,
26774 disableDoubleClickZoom: this.disableDoubleClickZoom,
26775 scrollwheel: this.scrollwheel,
26776 streetViewControl: this.streetViewControl,
26777 locationName: this.locationName,
26778 draggable: this.draggable,
26779 enableAutocomplete: this.enableAutocomplete,
26780 enableReverseGeocode: this.enableReverseGeocode
26783 var _marker = new google.maps.Marker({
26784 position: position,
26786 title: this.markerTitle,
26787 draggable: this.draggable
26794 location: position,
26795 radius: this.radius,
26796 locationName: this.locationName,
26797 addressComponents: {
26798 formatted_address: null,
26799 addressLine1: null,
26800 addressLine2: null,
26802 streetNumber: null,
26806 stateOrProvince: null
26809 domContainer: this.el.dom,
26810 geodecoder: new google.maps.Geocoder()
26814 drawCircle: function(center, radius, options)
26816 if (this.gMapContext.circle != null) {
26817 this.gMapContext.circle.setMap(null);
26821 options = Roo.apply({}, options, {
26822 strokeColor: "#0000FF",
26823 strokeOpacity: .35,
26825 fillColor: "#0000FF",
26829 options.map = this.gMapContext.map;
26830 options.radius = radius;
26831 options.center = center;
26832 this.gMapContext.circle = new google.maps.Circle(options);
26833 return this.gMapContext.circle;
26839 setPosition: function(location)
26841 this.gMapContext.location = location;
26842 this.gMapContext.marker.setPosition(location);
26843 this.gMapContext.map.panTo(location);
26844 this.drawCircle(location, this.gMapContext.radius, {});
26848 if (this.gMapContext.settings.enableReverseGeocode) {
26849 this.gMapContext.geodecoder.geocode({
26850 latLng: this.gMapContext.location
26851 }, function(results, status) {
26853 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26854 _this.gMapContext.locationName = results[0].formatted_address;
26855 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26857 _this.fireEvent('positionchanged', this, location);
26864 this.fireEvent('positionchanged', this, location);
26869 google.maps.event.trigger(this.gMapContext.map, "resize");
26871 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26873 this.fireEvent('resize', this);
26876 setPositionByLatLng: function(latitude, longitude)
26878 this.setPosition(new google.maps.LatLng(latitude, longitude));
26881 getCurrentPosition: function()
26884 latitude: this.gMapContext.location.lat(),
26885 longitude: this.gMapContext.location.lng()
26889 getAddressName: function()
26891 return this.gMapContext.locationName;
26894 getAddressComponents: function()
26896 return this.gMapContext.addressComponents;
26899 address_component_from_google_geocode: function(address_components)
26903 for (var i = 0; i < address_components.length; i++) {
26904 var component = address_components[i];
26905 if (component.types.indexOf("postal_code") >= 0) {
26906 result.postalCode = component.short_name;
26907 } else if (component.types.indexOf("street_number") >= 0) {
26908 result.streetNumber = component.short_name;
26909 } else if (component.types.indexOf("route") >= 0) {
26910 result.streetName = component.short_name;
26911 } else if (component.types.indexOf("neighborhood") >= 0) {
26912 result.city = component.short_name;
26913 } else if (component.types.indexOf("locality") >= 0) {
26914 result.city = component.short_name;
26915 } else if (component.types.indexOf("sublocality") >= 0) {
26916 result.district = component.short_name;
26917 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26918 result.stateOrProvince = component.short_name;
26919 } else if (component.types.indexOf("country") >= 0) {
26920 result.country = component.short_name;
26924 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26925 result.addressLine2 = "";
26929 setZoomLevel: function(zoom)
26931 this.gMapContext.map.setZoom(zoom);
26944 this.fireEvent('show', this);
26955 this.fireEvent('hide', this);
26960 Roo.apply(Roo.bootstrap.LocationPicker, {
26962 OverlayView : function(map, options)
26964 options = options || {};
26978 * @class Roo.bootstrap.Alert
26979 * @extends Roo.bootstrap.Component
26980 * Bootstrap Alert class
26981 * @cfg {String} title The title of alert
26982 * @cfg {String} html The content of alert
26983 * @cfg {String} weight ( success | info | warning | danger )
26984 * @cfg {String} faicon font-awesomeicon
26987 * Create a new alert
26988 * @param {Object} config The config object
26992 Roo.bootstrap.Alert = function(config){
26993 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26997 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27004 getAutoCreate : function()
27013 cls : 'roo-alert-icon'
27018 cls : 'roo-alert-title',
27023 cls : 'roo-alert-text',
27030 cfg.cn[0].cls += ' fa ' + this.faicon;
27034 cfg.cls += ' alert-' + this.weight;
27040 initEvents: function()
27042 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27045 setTitle : function(str)
27047 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27050 setText : function(str)
27052 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27055 setWeight : function(weight)
27058 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27061 this.weight = weight;
27063 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27066 setIcon : function(icon)
27069 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27072 this.faicon = icon;
27074 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27095 * @class Roo.bootstrap.UploadCropbox
27096 * @extends Roo.bootstrap.Component
27097 * Bootstrap UploadCropbox class
27098 * @cfg {String} emptyText show when image has been loaded
27099 * @cfg {String} rotateNotify show when image too small to rotate
27100 * @cfg {Number} errorTimeout default 3000
27101 * @cfg {Number} minWidth default 300
27102 * @cfg {Number} minHeight default 300
27103 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27104 * @cfg {Boolean} isDocument (true|false) default false
27105 * @cfg {String} url action url
27106 * @cfg {String} paramName default 'imageUpload'
27107 * @cfg {String} method default POST
27108 * @cfg {Boolean} loadMask (true|false) default true
27109 * @cfg {Boolean} loadingText default 'Loading...'
27112 * Create a new UploadCropbox
27113 * @param {Object} config The config object
27116 Roo.bootstrap.UploadCropbox = function(config){
27117 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27121 * @event beforeselectfile
27122 * Fire before select file
27123 * @param {Roo.bootstrap.UploadCropbox} this
27125 "beforeselectfile" : true,
27128 * Fire after initEvent
27129 * @param {Roo.bootstrap.UploadCropbox} this
27134 * Fire after initEvent
27135 * @param {Roo.bootstrap.UploadCropbox} this
27136 * @param {String} data
27141 * Fire when preparing the file data
27142 * @param {Roo.bootstrap.UploadCropbox} this
27143 * @param {Object} file
27148 * Fire when get exception
27149 * @param {Roo.bootstrap.UploadCropbox} this
27150 * @param {XMLHttpRequest} xhr
27152 "exception" : true,
27154 * @event beforeloadcanvas
27155 * Fire before load the canvas
27156 * @param {Roo.bootstrap.UploadCropbox} this
27157 * @param {String} src
27159 "beforeloadcanvas" : true,
27162 * Fire when trash image
27163 * @param {Roo.bootstrap.UploadCropbox} this
27168 * Fire when download the image
27169 * @param {Roo.bootstrap.UploadCropbox} this
27173 * @event footerbuttonclick
27174 * Fire when footerbuttonclick
27175 * @param {Roo.bootstrap.UploadCropbox} this
27176 * @param {String} type
27178 "footerbuttonclick" : true,
27182 * @param {Roo.bootstrap.UploadCropbox} this
27187 * Fire when rotate the image
27188 * @param {Roo.bootstrap.UploadCropbox} this
27189 * @param {String} pos
27194 * Fire when inspect the file
27195 * @param {Roo.bootstrap.UploadCropbox} this
27196 * @param {Object} file
27201 * Fire when xhr upload the file
27202 * @param {Roo.bootstrap.UploadCropbox} this
27203 * @param {Object} data
27208 * Fire when arrange the file data
27209 * @param {Roo.bootstrap.UploadCropbox} this
27210 * @param {Object} formData
27215 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27218 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27220 emptyText : 'Click to upload image',
27221 rotateNotify : 'Image is too small to rotate',
27222 errorTimeout : 3000,
27236 cropType : 'image/jpeg',
27238 canvasLoaded : false,
27239 isDocument : false,
27241 paramName : 'imageUpload',
27243 loadingText : 'Loading...',
27246 getAutoCreate : function()
27250 cls : 'roo-upload-cropbox',
27254 cls : 'roo-upload-cropbox-selector',
27259 cls : 'roo-upload-cropbox-body',
27260 style : 'cursor:pointer',
27264 cls : 'roo-upload-cropbox-preview'
27268 cls : 'roo-upload-cropbox-thumb'
27272 cls : 'roo-upload-cropbox-empty-notify',
27273 html : this.emptyText
27277 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27278 html : this.rotateNotify
27284 cls : 'roo-upload-cropbox-footer',
27287 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27297 onRender : function(ct, position)
27299 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27301 if (this.buttons.length) {
27303 Roo.each(this.buttons, function(bb) {
27305 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27307 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27313 this.maskEl = this.el;
27317 initEvents : function()
27319 this.urlAPI = (window.createObjectURL && window) ||
27320 (window.URL && URL.revokeObjectURL && URL) ||
27321 (window.webkitURL && webkitURL);
27323 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27324 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27326 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27327 this.selectorEl.hide();
27329 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27330 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27332 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27333 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27334 this.thumbEl.hide();
27336 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27337 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27339 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27340 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27341 this.errorEl.hide();
27343 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27344 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27345 this.footerEl.hide();
27347 this.setThumbBoxSize();
27353 this.fireEvent('initial', this);
27360 window.addEventListener("resize", function() { _this.resize(); } );
27362 this.bodyEl.on('click', this.beforeSelectFile, this);
27365 this.bodyEl.on('touchstart', this.onTouchStart, this);
27366 this.bodyEl.on('touchmove', this.onTouchMove, this);
27367 this.bodyEl.on('touchend', this.onTouchEnd, this);
27371 this.bodyEl.on('mousedown', this.onMouseDown, this);
27372 this.bodyEl.on('mousemove', this.onMouseMove, this);
27373 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27374 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27375 Roo.get(document).on('mouseup', this.onMouseUp, this);
27378 this.selectorEl.on('change', this.onFileSelected, this);
27384 this.baseScale = 1;
27386 this.baseRotate = 1;
27387 this.dragable = false;
27388 this.pinching = false;
27391 this.cropData = false;
27392 this.notifyEl.dom.innerHTML = this.emptyText;
27394 this.selectorEl.dom.value = '';
27398 resize : function()
27400 if(this.fireEvent('resize', this) != false){
27401 this.setThumbBoxPosition();
27402 this.setCanvasPosition();
27406 onFooterButtonClick : function(e, el, o, type)
27409 case 'rotate-left' :
27410 this.onRotateLeft(e);
27412 case 'rotate-right' :
27413 this.onRotateRight(e);
27416 this.beforeSelectFile(e);
27431 this.fireEvent('footerbuttonclick', this, type);
27434 beforeSelectFile : function(e)
27436 e.preventDefault();
27438 if(this.fireEvent('beforeselectfile', this) != false){
27439 this.selectorEl.dom.click();
27443 onFileSelected : function(e)
27445 e.preventDefault();
27447 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27451 var file = this.selectorEl.dom.files[0];
27453 if(this.fireEvent('inspect', this, file) != false){
27454 this.prepare(file);
27459 trash : function(e)
27461 this.fireEvent('trash', this);
27464 download : function(e)
27466 this.fireEvent('download', this);
27469 loadCanvas : function(src)
27471 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27475 this.imageEl = document.createElement('img');
27479 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27481 this.imageEl.src = src;
27485 onLoadCanvas : function()
27487 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27488 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27490 this.bodyEl.un('click', this.beforeSelectFile, this);
27492 this.notifyEl.hide();
27493 this.thumbEl.show();
27494 this.footerEl.show();
27496 this.baseRotateLevel();
27498 if(this.isDocument){
27499 this.setThumbBoxSize();
27502 this.setThumbBoxPosition();
27504 this.baseScaleLevel();
27510 this.canvasLoaded = true;
27513 this.maskEl.unmask();
27518 setCanvasPosition : function()
27520 if(!this.canvasEl){
27524 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27525 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27527 this.previewEl.setLeft(pw);
27528 this.previewEl.setTop(ph);
27532 onMouseDown : function(e)
27536 this.dragable = true;
27537 this.pinching = false;
27539 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27540 this.dragable = false;
27544 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27545 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27549 onMouseMove : function(e)
27553 if(!this.canvasLoaded){
27557 if (!this.dragable){
27561 var minX = Math.ceil(this.thumbEl.getLeft(true));
27562 var minY = Math.ceil(this.thumbEl.getTop(true));
27564 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27565 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27567 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27568 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27570 x = x - this.mouseX;
27571 y = y - this.mouseY;
27573 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27574 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27576 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27577 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27579 this.previewEl.setLeft(bgX);
27580 this.previewEl.setTop(bgY);
27582 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27583 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27586 onMouseUp : function(e)
27590 this.dragable = false;
27593 onMouseWheel : function(e)
27597 this.startScale = this.scale;
27599 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27601 if(!this.zoomable()){
27602 this.scale = this.startScale;
27611 zoomable : function()
27613 var minScale = this.thumbEl.getWidth() / this.minWidth;
27615 if(this.minWidth < this.minHeight){
27616 minScale = this.thumbEl.getHeight() / this.minHeight;
27619 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27620 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27624 (this.rotate == 0 || this.rotate == 180) &&
27626 width > this.imageEl.OriginWidth ||
27627 height > this.imageEl.OriginHeight ||
27628 (width < this.minWidth && height < this.minHeight)
27636 (this.rotate == 90 || this.rotate == 270) &&
27638 width > this.imageEl.OriginWidth ||
27639 height > this.imageEl.OriginHeight ||
27640 (width < this.minHeight && height < this.minWidth)
27647 !this.isDocument &&
27648 (this.rotate == 0 || this.rotate == 180) &&
27650 width < this.minWidth ||
27651 width > this.imageEl.OriginWidth ||
27652 height < this.minHeight ||
27653 height > this.imageEl.OriginHeight
27660 !this.isDocument &&
27661 (this.rotate == 90 || this.rotate == 270) &&
27663 width < this.minHeight ||
27664 width > this.imageEl.OriginWidth ||
27665 height < this.minWidth ||
27666 height > this.imageEl.OriginHeight
27676 onRotateLeft : function(e)
27678 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27680 var minScale = this.thumbEl.getWidth() / this.minWidth;
27682 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27683 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27685 this.startScale = this.scale;
27687 while (this.getScaleLevel() < minScale){
27689 this.scale = this.scale + 1;
27691 if(!this.zoomable()){
27696 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27697 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27702 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27709 this.scale = this.startScale;
27711 this.onRotateFail();
27716 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27718 if(this.isDocument){
27719 this.setThumbBoxSize();
27720 this.setThumbBoxPosition();
27721 this.setCanvasPosition();
27726 this.fireEvent('rotate', this, 'left');
27730 onRotateRight : function(e)
27732 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27734 var minScale = this.thumbEl.getWidth() / this.minWidth;
27736 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27737 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27739 this.startScale = this.scale;
27741 while (this.getScaleLevel() < minScale){
27743 this.scale = this.scale + 1;
27745 if(!this.zoomable()){
27750 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27751 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27756 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27763 this.scale = this.startScale;
27765 this.onRotateFail();
27770 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27772 if(this.isDocument){
27773 this.setThumbBoxSize();
27774 this.setThumbBoxPosition();
27775 this.setCanvasPosition();
27780 this.fireEvent('rotate', this, 'right');
27783 onRotateFail : function()
27785 this.errorEl.show(true);
27789 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27794 this.previewEl.dom.innerHTML = '';
27796 var canvasEl = document.createElement("canvas");
27798 var contextEl = canvasEl.getContext("2d");
27800 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27801 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27802 var center = this.imageEl.OriginWidth / 2;
27804 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27805 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27806 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27807 center = this.imageEl.OriginHeight / 2;
27810 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27812 contextEl.translate(center, center);
27813 contextEl.rotate(this.rotate * Math.PI / 180);
27815 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27817 this.canvasEl = document.createElement("canvas");
27819 this.contextEl = this.canvasEl.getContext("2d");
27821 switch (this.rotate) {
27824 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27825 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27827 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27832 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27833 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27835 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27836 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27840 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27845 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27846 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27848 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27849 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);
27853 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);
27858 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27859 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27861 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27862 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27866 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);
27873 this.previewEl.appendChild(this.canvasEl);
27875 this.setCanvasPosition();
27880 if(!this.canvasLoaded){
27884 var imageCanvas = document.createElement("canvas");
27886 var imageContext = imageCanvas.getContext("2d");
27888 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27889 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27891 var center = imageCanvas.width / 2;
27893 imageContext.translate(center, center);
27895 imageContext.rotate(this.rotate * Math.PI / 180);
27897 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27899 var canvas = document.createElement("canvas");
27901 var context = canvas.getContext("2d");
27903 canvas.width = this.minWidth;
27904 canvas.height = this.minHeight;
27906 switch (this.rotate) {
27909 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27910 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27912 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27913 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27915 var targetWidth = this.minWidth - 2 * x;
27916 var targetHeight = this.minHeight - 2 * y;
27920 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27921 scale = targetWidth / width;
27924 if(x > 0 && y == 0){
27925 scale = targetHeight / height;
27928 if(x > 0 && y > 0){
27929 scale = targetWidth / width;
27931 if(width < height){
27932 scale = targetHeight / height;
27936 context.scale(scale, scale);
27938 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27939 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27941 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27942 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27944 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27949 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27950 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27952 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27953 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27955 var targetWidth = this.minWidth - 2 * x;
27956 var targetHeight = this.minHeight - 2 * y;
27960 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27961 scale = targetWidth / width;
27964 if(x > 0 && y == 0){
27965 scale = targetHeight / height;
27968 if(x > 0 && y > 0){
27969 scale = targetWidth / width;
27971 if(width < height){
27972 scale = targetHeight / height;
27976 context.scale(scale, scale);
27978 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27979 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27981 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27982 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27984 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27986 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27991 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27992 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27994 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27995 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27997 var targetWidth = this.minWidth - 2 * x;
27998 var targetHeight = this.minHeight - 2 * y;
28002 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28003 scale = targetWidth / width;
28006 if(x > 0 && y == 0){
28007 scale = targetHeight / height;
28010 if(x > 0 && y > 0){
28011 scale = targetWidth / width;
28013 if(width < height){
28014 scale = targetHeight / height;
28018 context.scale(scale, scale);
28020 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28021 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28023 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28024 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28026 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28027 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28029 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28034 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28035 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28037 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28038 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28040 var targetWidth = this.minWidth - 2 * x;
28041 var targetHeight = this.minHeight - 2 * y;
28045 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28046 scale = targetWidth / width;
28049 if(x > 0 && y == 0){
28050 scale = targetHeight / height;
28053 if(x > 0 && y > 0){
28054 scale = targetWidth / width;
28056 if(width < height){
28057 scale = targetHeight / height;
28061 context.scale(scale, scale);
28063 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28064 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28066 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28067 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28069 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28071 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28078 this.cropData = canvas.toDataURL(this.cropType);
28080 if(this.fireEvent('crop', this, this.cropData) !== false){
28081 this.process(this.file, this.cropData);
28088 setThumbBoxSize : function()
28092 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28093 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28094 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28096 this.minWidth = width;
28097 this.minHeight = height;
28099 if(this.rotate == 90 || this.rotate == 270){
28100 this.minWidth = height;
28101 this.minHeight = width;
28106 width = Math.ceil(this.minWidth * height / this.minHeight);
28108 if(this.minWidth > this.minHeight){
28110 height = Math.ceil(this.minHeight * width / this.minWidth);
28113 this.thumbEl.setStyle({
28114 width : width + 'px',
28115 height : height + 'px'
28122 setThumbBoxPosition : function()
28124 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28125 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28127 this.thumbEl.setLeft(x);
28128 this.thumbEl.setTop(y);
28132 baseRotateLevel : function()
28134 this.baseRotate = 1;
28137 typeof(this.exif) != 'undefined' &&
28138 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28139 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28141 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28144 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28148 baseScaleLevel : function()
28152 if(this.isDocument){
28154 if(this.baseRotate == 6 || this.baseRotate == 8){
28156 height = this.thumbEl.getHeight();
28157 this.baseScale = height / this.imageEl.OriginWidth;
28159 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28160 width = this.thumbEl.getWidth();
28161 this.baseScale = width / this.imageEl.OriginHeight;
28167 height = this.thumbEl.getHeight();
28168 this.baseScale = height / this.imageEl.OriginHeight;
28170 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28171 width = this.thumbEl.getWidth();
28172 this.baseScale = width / this.imageEl.OriginWidth;
28178 if(this.baseRotate == 6 || this.baseRotate == 8){
28180 width = this.thumbEl.getHeight();
28181 this.baseScale = width / this.imageEl.OriginHeight;
28183 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28184 height = this.thumbEl.getWidth();
28185 this.baseScale = height / this.imageEl.OriginHeight;
28188 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28189 height = this.thumbEl.getWidth();
28190 this.baseScale = height / this.imageEl.OriginHeight;
28192 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28193 width = this.thumbEl.getHeight();
28194 this.baseScale = width / this.imageEl.OriginWidth;
28201 width = this.thumbEl.getWidth();
28202 this.baseScale = width / this.imageEl.OriginWidth;
28204 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28205 height = this.thumbEl.getHeight();
28206 this.baseScale = height / this.imageEl.OriginHeight;
28209 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28211 height = this.thumbEl.getHeight();
28212 this.baseScale = height / this.imageEl.OriginHeight;
28214 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28215 width = this.thumbEl.getWidth();
28216 this.baseScale = width / this.imageEl.OriginWidth;
28224 getScaleLevel : function()
28226 return this.baseScale * Math.pow(1.1, this.scale);
28229 onTouchStart : function(e)
28231 if(!this.canvasLoaded){
28232 this.beforeSelectFile(e);
28236 var touches = e.browserEvent.touches;
28242 if(touches.length == 1){
28243 this.onMouseDown(e);
28247 if(touches.length != 2){
28253 for(var i = 0, finger; finger = touches[i]; i++){
28254 coords.push(finger.pageX, finger.pageY);
28257 var x = Math.pow(coords[0] - coords[2], 2);
28258 var y = Math.pow(coords[1] - coords[3], 2);
28260 this.startDistance = Math.sqrt(x + y);
28262 this.startScale = this.scale;
28264 this.pinching = true;
28265 this.dragable = false;
28269 onTouchMove : function(e)
28271 if(!this.pinching && !this.dragable){
28275 var touches = e.browserEvent.touches;
28282 this.onMouseMove(e);
28288 for(var i = 0, finger; finger = touches[i]; i++){
28289 coords.push(finger.pageX, finger.pageY);
28292 var x = Math.pow(coords[0] - coords[2], 2);
28293 var y = Math.pow(coords[1] - coords[3], 2);
28295 this.endDistance = Math.sqrt(x + y);
28297 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28299 if(!this.zoomable()){
28300 this.scale = this.startScale;
28308 onTouchEnd : function(e)
28310 this.pinching = false;
28311 this.dragable = false;
28315 process : function(file, crop)
28318 this.maskEl.mask(this.loadingText);
28321 this.xhr = new XMLHttpRequest();
28323 file.xhr = this.xhr;
28325 this.xhr.open(this.method, this.url, true);
28328 "Accept": "application/json",
28329 "Cache-Control": "no-cache",
28330 "X-Requested-With": "XMLHttpRequest"
28333 for (var headerName in headers) {
28334 var headerValue = headers[headerName];
28336 this.xhr.setRequestHeader(headerName, headerValue);
28342 this.xhr.onload = function()
28344 _this.xhrOnLoad(_this.xhr);
28347 this.xhr.onerror = function()
28349 _this.xhrOnError(_this.xhr);
28352 var formData = new FormData();
28354 formData.append('returnHTML', 'NO');
28357 formData.append('crop', crop);
28360 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28361 formData.append(this.paramName, file, file.name);
28364 if(typeof(file.filename) != 'undefined'){
28365 formData.append('filename', file.filename);
28368 if(typeof(file.mimetype) != 'undefined'){
28369 formData.append('mimetype', file.mimetype);
28372 if(this.fireEvent('arrange', this, formData) != false){
28373 this.xhr.send(formData);
28377 xhrOnLoad : function(xhr)
28380 this.maskEl.unmask();
28383 if (xhr.readyState !== 4) {
28384 this.fireEvent('exception', this, xhr);
28388 var response = Roo.decode(xhr.responseText);
28390 if(!response.success){
28391 this.fireEvent('exception', this, xhr);
28395 var response = Roo.decode(xhr.responseText);
28397 this.fireEvent('upload', this, response);
28401 xhrOnError : function()
28404 this.maskEl.unmask();
28407 Roo.log('xhr on error');
28409 var response = Roo.decode(xhr.responseText);
28415 prepare : function(file)
28418 this.maskEl.mask(this.loadingText);
28424 if(typeof(file) === 'string'){
28425 this.loadCanvas(file);
28429 if(!file || !this.urlAPI){
28434 this.cropType = file.type;
28438 if(this.fireEvent('prepare', this, this.file) != false){
28440 var reader = new FileReader();
28442 reader.onload = function (e) {
28443 if (e.target.error) {
28444 Roo.log(e.target.error);
28448 var buffer = e.target.result,
28449 dataView = new DataView(buffer),
28451 maxOffset = dataView.byteLength - 4,
28455 if (dataView.getUint16(0) === 0xffd8) {
28456 while (offset < maxOffset) {
28457 markerBytes = dataView.getUint16(offset);
28459 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28460 markerLength = dataView.getUint16(offset + 2) + 2;
28461 if (offset + markerLength > dataView.byteLength) {
28462 Roo.log('Invalid meta data: Invalid segment size.');
28466 if(markerBytes == 0xffe1){
28467 _this.parseExifData(
28474 offset += markerLength;
28484 var url = _this.urlAPI.createObjectURL(_this.file);
28486 _this.loadCanvas(url);
28491 reader.readAsArrayBuffer(this.file);
28497 parseExifData : function(dataView, offset, length)
28499 var tiffOffset = offset + 10,
28503 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28504 // No Exif data, might be XMP data instead
28508 // Check for the ASCII code for "Exif" (0x45786966):
28509 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28510 // No Exif data, might be XMP data instead
28513 if (tiffOffset + 8 > dataView.byteLength) {
28514 Roo.log('Invalid Exif data: Invalid segment size.');
28517 // Check for the two null bytes:
28518 if (dataView.getUint16(offset + 8) !== 0x0000) {
28519 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28522 // Check the byte alignment:
28523 switch (dataView.getUint16(tiffOffset)) {
28525 littleEndian = true;
28528 littleEndian = false;
28531 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28534 // Check for the TIFF tag marker (0x002A):
28535 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28536 Roo.log('Invalid Exif data: Missing TIFF marker.');
28539 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28540 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28542 this.parseExifTags(
28545 tiffOffset + dirOffset,
28550 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28555 if (dirOffset + 6 > dataView.byteLength) {
28556 Roo.log('Invalid Exif data: Invalid directory offset.');
28559 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28560 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28561 if (dirEndOffset + 4 > dataView.byteLength) {
28562 Roo.log('Invalid Exif data: Invalid directory size.');
28565 for (i = 0; i < tagsNumber; i += 1) {
28569 dirOffset + 2 + 12 * i, // tag offset
28573 // Return the offset to the next directory:
28574 return dataView.getUint32(dirEndOffset, littleEndian);
28577 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28579 var tag = dataView.getUint16(offset, littleEndian);
28581 this.exif[tag] = this.getExifValue(
28585 dataView.getUint16(offset + 2, littleEndian), // tag type
28586 dataView.getUint32(offset + 4, littleEndian), // tag length
28591 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28593 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28602 Roo.log('Invalid Exif data: Invalid tag type.');
28606 tagSize = tagType.size * length;
28607 // Determine if the value is contained in the dataOffset bytes,
28608 // or if the value at the dataOffset is a pointer to the actual data:
28609 dataOffset = tagSize > 4 ?
28610 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28611 if (dataOffset + tagSize > dataView.byteLength) {
28612 Roo.log('Invalid Exif data: Invalid data offset.');
28615 if (length === 1) {
28616 return tagType.getValue(dataView, dataOffset, littleEndian);
28619 for (i = 0; i < length; i += 1) {
28620 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28623 if (tagType.ascii) {
28625 // Concatenate the chars:
28626 for (i = 0; i < values.length; i += 1) {
28628 // Ignore the terminating NULL byte(s):
28629 if (c === '\u0000') {
28641 Roo.apply(Roo.bootstrap.UploadCropbox, {
28643 'Orientation': 0x0112
28647 1: 0, //'top-left',
28649 3: 180, //'bottom-right',
28650 // 4: 'bottom-left',
28652 6: 90, //'right-top',
28653 // 7: 'right-bottom',
28654 8: 270 //'left-bottom'
28658 // byte, 8-bit unsigned int:
28660 getValue: function (dataView, dataOffset) {
28661 return dataView.getUint8(dataOffset);
28665 // ascii, 8-bit byte:
28667 getValue: function (dataView, dataOffset) {
28668 return String.fromCharCode(dataView.getUint8(dataOffset));
28673 // short, 16 bit int:
28675 getValue: function (dataView, dataOffset, littleEndian) {
28676 return dataView.getUint16(dataOffset, littleEndian);
28680 // long, 32 bit int:
28682 getValue: function (dataView, dataOffset, littleEndian) {
28683 return dataView.getUint32(dataOffset, littleEndian);
28687 // rational = two long values, first is numerator, second is denominator:
28689 getValue: function (dataView, dataOffset, littleEndian) {
28690 return dataView.getUint32(dataOffset, littleEndian) /
28691 dataView.getUint32(dataOffset + 4, littleEndian);
28695 // slong, 32 bit signed int:
28697 getValue: function (dataView, dataOffset, littleEndian) {
28698 return dataView.getInt32(dataOffset, littleEndian);
28702 // srational, two slongs, first is numerator, second is denominator:
28704 getValue: function (dataView, dataOffset, littleEndian) {
28705 return dataView.getInt32(dataOffset, littleEndian) /
28706 dataView.getInt32(dataOffset + 4, littleEndian);
28716 cls : 'btn-group roo-upload-cropbox-rotate-left',
28717 action : 'rotate-left',
28721 cls : 'btn btn-default',
28722 html : '<i class="fa fa-undo"></i>'
28728 cls : 'btn-group roo-upload-cropbox-picture',
28729 action : 'picture',
28733 cls : 'btn btn-default',
28734 html : '<i class="fa fa-picture-o"></i>'
28740 cls : 'btn-group roo-upload-cropbox-rotate-right',
28741 action : 'rotate-right',
28745 cls : 'btn btn-default',
28746 html : '<i class="fa fa-repeat"></i>'
28754 cls : 'btn-group roo-upload-cropbox-rotate-left',
28755 action : 'rotate-left',
28759 cls : 'btn btn-default',
28760 html : '<i class="fa fa-undo"></i>'
28766 cls : 'btn-group roo-upload-cropbox-download',
28767 action : 'download',
28771 cls : 'btn btn-default',
28772 html : '<i class="fa fa-download"></i>'
28778 cls : 'btn-group roo-upload-cropbox-crop',
28783 cls : 'btn btn-default',
28784 html : '<i class="fa fa-crop"></i>'
28790 cls : 'btn-group roo-upload-cropbox-trash',
28795 cls : 'btn btn-default',
28796 html : '<i class="fa fa-trash"></i>'
28802 cls : 'btn-group roo-upload-cropbox-rotate-right',
28803 action : 'rotate-right',
28807 cls : 'btn btn-default',
28808 html : '<i class="fa fa-repeat"></i>'
28816 cls : 'btn-group roo-upload-cropbox-rotate-left',
28817 action : 'rotate-left',
28821 cls : 'btn btn-default',
28822 html : '<i class="fa fa-undo"></i>'
28828 cls : 'btn-group roo-upload-cropbox-rotate-right',
28829 action : 'rotate-right',
28833 cls : 'btn btn-default',
28834 html : '<i class="fa fa-repeat"></i>'
28847 * @class Roo.bootstrap.DocumentManager
28848 * @extends Roo.bootstrap.Component
28849 * Bootstrap DocumentManager class
28850 * @cfg {String} paramName default 'imageUpload'
28851 * @cfg {String} toolTipName default 'filename'
28852 * @cfg {String} method default POST
28853 * @cfg {String} url action url
28854 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28855 * @cfg {Boolean} multiple multiple upload default true
28856 * @cfg {Number} thumbSize default 300
28857 * @cfg {String} fieldLabel
28858 * @cfg {Number} labelWidth default 4
28859 * @cfg {String} labelAlign (left|top) default left
28860 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28861 * @cfg {Number} labellg set the width of label (1-12)
28862 * @cfg {Number} labelmd set the width of label (1-12)
28863 * @cfg {Number} labelsm set the width of label (1-12)
28864 * @cfg {Number} labelxs set the width of label (1-12)
28867 * Create a new DocumentManager
28868 * @param {Object} config The config object
28871 Roo.bootstrap.DocumentManager = function(config){
28872 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28875 this.delegates = [];
28880 * Fire when initial the DocumentManager
28881 * @param {Roo.bootstrap.DocumentManager} this
28886 * inspect selected file
28887 * @param {Roo.bootstrap.DocumentManager} this
28888 * @param {File} file
28893 * Fire when xhr load exception
28894 * @param {Roo.bootstrap.DocumentManager} this
28895 * @param {XMLHttpRequest} xhr
28897 "exception" : true,
28899 * @event afterupload
28900 * Fire when xhr load exception
28901 * @param {Roo.bootstrap.DocumentManager} this
28902 * @param {XMLHttpRequest} xhr
28904 "afterupload" : true,
28907 * prepare the form data
28908 * @param {Roo.bootstrap.DocumentManager} this
28909 * @param {Object} formData
28914 * Fire when remove the file
28915 * @param {Roo.bootstrap.DocumentManager} this
28916 * @param {Object} file
28921 * Fire after refresh the file
28922 * @param {Roo.bootstrap.DocumentManager} this
28927 * Fire after click the image
28928 * @param {Roo.bootstrap.DocumentManager} this
28929 * @param {Object} file
28934 * Fire when upload a image and editable set to true
28935 * @param {Roo.bootstrap.DocumentManager} this
28936 * @param {Object} file
28940 * @event beforeselectfile
28941 * Fire before select file
28942 * @param {Roo.bootstrap.DocumentManager} this
28944 "beforeselectfile" : true,
28947 * Fire before process file
28948 * @param {Roo.bootstrap.DocumentManager} this
28949 * @param {Object} file
28953 * @event previewrendered
28954 * Fire when preview rendered
28955 * @param {Roo.bootstrap.DocumentManager} this
28956 * @param {Object} file
28958 "previewrendered" : true,
28961 "previewResize" : true
28966 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28975 paramName : 'imageUpload',
28976 toolTipName : 'filename',
28979 labelAlign : 'left',
28989 getAutoCreate : function()
28991 var managerWidget = {
28993 cls : 'roo-document-manager',
28997 cls : 'roo-document-manager-selector',
29002 cls : 'roo-document-manager-uploader',
29006 cls : 'roo-document-manager-upload-btn',
29007 html : '<i class="fa fa-plus"></i>'
29018 cls : 'column col-md-12',
29023 if(this.fieldLabel.length){
29028 cls : 'column col-md-12',
29029 html : this.fieldLabel
29033 cls : 'column col-md-12',
29038 if(this.labelAlign == 'left'){
29043 html : this.fieldLabel
29052 if(this.labelWidth > 12){
29053 content[0].style = "width: " + this.labelWidth + 'px';
29056 if(this.labelWidth < 13 && this.labelmd == 0){
29057 this.labelmd = this.labelWidth;
29060 if(this.labellg > 0){
29061 content[0].cls += ' col-lg-' + this.labellg;
29062 content[1].cls += ' col-lg-' + (12 - this.labellg);
29065 if(this.labelmd > 0){
29066 content[0].cls += ' col-md-' + this.labelmd;
29067 content[1].cls += ' col-md-' + (12 - this.labelmd);
29070 if(this.labelsm > 0){
29071 content[0].cls += ' col-sm-' + this.labelsm;
29072 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29075 if(this.labelxs > 0){
29076 content[0].cls += ' col-xs-' + this.labelxs;
29077 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29085 cls : 'row clearfix',
29093 initEvents : function()
29095 this.managerEl = this.el.select('.roo-document-manager', true).first();
29096 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29098 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29099 this.selectorEl.hide();
29102 this.selectorEl.attr('multiple', 'multiple');
29105 this.selectorEl.on('change', this.onFileSelected, this);
29107 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29108 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29110 this.uploader.on('click', this.onUploaderClick, this);
29112 this.renderProgressDialog();
29116 window.addEventListener("resize", function() { _this.refresh(); } );
29118 this.fireEvent('initial', this);
29121 renderProgressDialog : function()
29125 this.progressDialog = new Roo.bootstrap.Modal({
29126 cls : 'roo-document-manager-progress-dialog',
29127 allow_close : false,
29137 btnclick : function() {
29138 _this.uploadCancel();
29144 this.progressDialog.render(Roo.get(document.body));
29146 this.progress = new Roo.bootstrap.Progress({
29147 cls : 'roo-document-manager-progress',
29152 this.progress.render(this.progressDialog.getChildContainer());
29154 this.progressBar = new Roo.bootstrap.ProgressBar({
29155 cls : 'roo-document-manager-progress-bar',
29158 aria_valuemax : 12,
29162 this.progressBar.render(this.progress.getChildContainer());
29165 onUploaderClick : function(e)
29167 e.preventDefault();
29169 if(this.fireEvent('beforeselectfile', this) != false){
29170 this.selectorEl.dom.click();
29175 onFileSelected : function(e)
29177 e.preventDefault();
29179 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29183 Roo.each(this.selectorEl.dom.files, function(file){
29184 if(this.fireEvent('inspect', this, file) != false){
29185 this.files.push(file);
29195 this.selectorEl.dom.value = '';
29197 if(!this.files || !this.files.length){
29201 if(this.boxes > 0 && this.files.length > this.boxes){
29202 this.files = this.files.slice(0, this.boxes);
29205 this.uploader.show();
29207 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29208 this.uploader.hide();
29217 Roo.each(this.files, function(file){
29219 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29220 var f = this.renderPreview(file);
29225 if(file.type.indexOf('image') != -1){
29226 this.delegates.push(
29228 _this.process(file);
29229 }).createDelegate(this)
29237 _this.process(file);
29238 }).createDelegate(this)
29243 this.files = files;
29245 this.delegates = this.delegates.concat(docs);
29247 if(!this.delegates.length){
29252 this.progressBar.aria_valuemax = this.delegates.length;
29259 arrange : function()
29261 if(!this.delegates.length){
29262 this.progressDialog.hide();
29267 var delegate = this.delegates.shift();
29269 this.progressDialog.show();
29271 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29273 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29278 refresh : function()
29280 this.uploader.show();
29282 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29283 this.uploader.hide();
29286 Roo.isTouch ? this.closable(false) : this.closable(true);
29288 this.fireEvent('refresh', this);
29291 onRemove : function(e, el, o)
29293 e.preventDefault();
29295 this.fireEvent('remove', this, o);
29299 remove : function(o)
29303 Roo.each(this.files, function(file){
29304 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29313 this.files = files;
29320 Roo.each(this.files, function(file){
29325 file.target.remove();
29334 onClick : function(e, el, o)
29336 e.preventDefault();
29338 this.fireEvent('click', this, o);
29342 closable : function(closable)
29344 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29346 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29358 xhrOnLoad : function(xhr)
29360 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29364 if (xhr.readyState !== 4) {
29366 this.fireEvent('exception', this, xhr);
29370 var response = Roo.decode(xhr.responseText);
29372 if(!response.success){
29374 this.fireEvent('exception', this, xhr);
29378 var file = this.renderPreview(response.data);
29380 this.files.push(file);
29384 this.fireEvent('afterupload', this, xhr);
29388 xhrOnError : function(xhr)
29390 Roo.log('xhr on error');
29392 var response = Roo.decode(xhr.responseText);
29399 process : function(file)
29401 if(this.fireEvent('process', this, file) !== false){
29402 if(this.editable && file.type.indexOf('image') != -1){
29403 this.fireEvent('edit', this, file);
29407 this.uploadStart(file, false);
29414 uploadStart : function(file, crop)
29416 this.xhr = new XMLHttpRequest();
29418 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29423 file.xhr = this.xhr;
29425 this.managerEl.createChild({
29427 cls : 'roo-document-manager-loading',
29431 tooltip : file.name,
29432 cls : 'roo-document-manager-thumb',
29433 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29439 this.xhr.open(this.method, this.url, true);
29442 "Accept": "application/json",
29443 "Cache-Control": "no-cache",
29444 "X-Requested-With": "XMLHttpRequest"
29447 for (var headerName in headers) {
29448 var headerValue = headers[headerName];
29450 this.xhr.setRequestHeader(headerName, headerValue);
29456 this.xhr.onload = function()
29458 _this.xhrOnLoad(_this.xhr);
29461 this.xhr.onerror = function()
29463 _this.xhrOnError(_this.xhr);
29466 var formData = new FormData();
29468 formData.append('returnHTML', 'NO');
29471 formData.append('crop', crop);
29474 formData.append(this.paramName, file, file.name);
29481 if(this.fireEvent('prepare', this, formData, options) != false){
29483 if(options.manually){
29487 this.xhr.send(formData);
29491 this.uploadCancel();
29494 uploadCancel : function()
29500 this.delegates = [];
29502 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29509 renderPreview : function(file)
29511 if(typeof(file.target) != 'undefined' && file.target){
29515 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29517 var previewEl = this.managerEl.createChild({
29519 cls : 'roo-document-manager-preview',
29523 tooltip : file[this.toolTipName],
29524 cls : 'roo-document-manager-thumb',
29525 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29530 html : '<i class="fa fa-times-circle"></i>'
29535 var close = previewEl.select('button.close', true).first();
29537 close.on('click', this.onRemove, this, file);
29539 file.target = previewEl;
29541 var image = previewEl.select('img', true).first();
29545 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29547 image.on('click', this.onClick, this, file);
29549 this.fireEvent('previewrendered', this, file);
29555 onPreviewLoad : function(file, image)
29557 if(typeof(file.target) == 'undefined' || !file.target){
29561 var width = image.dom.naturalWidth || image.dom.width;
29562 var height = image.dom.naturalHeight || image.dom.height;
29564 if(!this.previewResize) {
29568 if(width > height){
29569 file.target.addClass('wide');
29573 file.target.addClass('tall');
29578 uploadFromSource : function(file, crop)
29580 this.xhr = new XMLHttpRequest();
29582 this.managerEl.createChild({
29584 cls : 'roo-document-manager-loading',
29588 tooltip : file.name,
29589 cls : 'roo-document-manager-thumb',
29590 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29596 this.xhr.open(this.method, this.url, true);
29599 "Accept": "application/json",
29600 "Cache-Control": "no-cache",
29601 "X-Requested-With": "XMLHttpRequest"
29604 for (var headerName in headers) {
29605 var headerValue = headers[headerName];
29607 this.xhr.setRequestHeader(headerName, headerValue);
29613 this.xhr.onload = function()
29615 _this.xhrOnLoad(_this.xhr);
29618 this.xhr.onerror = function()
29620 _this.xhrOnError(_this.xhr);
29623 var formData = new FormData();
29625 formData.append('returnHTML', 'NO');
29627 formData.append('crop', crop);
29629 if(typeof(file.filename) != 'undefined'){
29630 formData.append('filename', file.filename);
29633 if(typeof(file.mimetype) != 'undefined'){
29634 formData.append('mimetype', file.mimetype);
29639 if(this.fireEvent('prepare', this, formData) != false){
29640 this.xhr.send(formData);
29650 * @class Roo.bootstrap.DocumentViewer
29651 * @extends Roo.bootstrap.Component
29652 * Bootstrap DocumentViewer class
29653 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29654 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29657 * Create a new DocumentViewer
29658 * @param {Object} config The config object
29661 Roo.bootstrap.DocumentViewer = function(config){
29662 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29667 * Fire after initEvent
29668 * @param {Roo.bootstrap.DocumentViewer} this
29674 * @param {Roo.bootstrap.DocumentViewer} this
29679 * Fire after download button
29680 * @param {Roo.bootstrap.DocumentViewer} this
29685 * Fire after trash button
29686 * @param {Roo.bootstrap.DocumentViewer} this
29693 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29695 showDownload : true,
29699 getAutoCreate : function()
29703 cls : 'roo-document-viewer',
29707 cls : 'roo-document-viewer-body',
29711 cls : 'roo-document-viewer-thumb',
29715 cls : 'roo-document-viewer-image'
29723 cls : 'roo-document-viewer-footer',
29726 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29730 cls : 'btn-group roo-document-viewer-download',
29734 cls : 'btn btn-default',
29735 html : '<i class="fa fa-download"></i>'
29741 cls : 'btn-group roo-document-viewer-trash',
29745 cls : 'btn btn-default',
29746 html : '<i class="fa fa-trash"></i>'
29759 initEvents : function()
29761 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29762 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29764 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29765 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29767 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29768 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29770 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29771 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29773 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29774 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29776 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29777 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29779 this.bodyEl.on('click', this.onClick, this);
29780 this.downloadBtn.on('click', this.onDownload, this);
29781 this.trashBtn.on('click', this.onTrash, this);
29783 this.downloadBtn.hide();
29784 this.trashBtn.hide();
29786 if(this.showDownload){
29787 this.downloadBtn.show();
29790 if(this.showTrash){
29791 this.trashBtn.show();
29794 if(!this.showDownload && !this.showTrash) {
29795 this.footerEl.hide();
29800 initial : function()
29802 this.fireEvent('initial', this);
29806 onClick : function(e)
29808 e.preventDefault();
29810 this.fireEvent('click', this);
29813 onDownload : function(e)
29815 e.preventDefault();
29817 this.fireEvent('download', this);
29820 onTrash : function(e)
29822 e.preventDefault();
29824 this.fireEvent('trash', this);
29836 * @class Roo.bootstrap.NavProgressBar
29837 * @extends Roo.bootstrap.Component
29838 * Bootstrap NavProgressBar class
29841 * Create a new nav progress bar
29842 * @param {Object} config The config object
29845 Roo.bootstrap.NavProgressBar = function(config){
29846 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29848 this.bullets = this.bullets || [];
29850 // Roo.bootstrap.NavProgressBar.register(this);
29854 * Fires when the active item changes
29855 * @param {Roo.bootstrap.NavProgressBar} this
29856 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29857 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29864 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29869 getAutoCreate : function()
29871 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29875 cls : 'roo-navigation-bar-group',
29879 cls : 'roo-navigation-top-bar'
29883 cls : 'roo-navigation-bullets-bar',
29887 cls : 'roo-navigation-bar'
29894 cls : 'roo-navigation-bottom-bar'
29904 initEvents: function()
29909 onRender : function(ct, position)
29911 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29913 if(this.bullets.length){
29914 Roo.each(this.bullets, function(b){
29923 addItem : function(cfg)
29925 var item = new Roo.bootstrap.NavProgressItem(cfg);
29927 item.parentId = this.id;
29928 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29931 var top = new Roo.bootstrap.Element({
29933 cls : 'roo-navigation-bar-text'
29936 var bottom = new Roo.bootstrap.Element({
29938 cls : 'roo-navigation-bar-text'
29941 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29942 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29944 var topText = new Roo.bootstrap.Element({
29946 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29949 var bottomText = new Roo.bootstrap.Element({
29951 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29954 topText.onRender(top.el, null);
29955 bottomText.onRender(bottom.el, null);
29958 item.bottomEl = bottom;
29961 this.barItems.push(item);
29966 getActive : function()
29968 var active = false;
29970 Roo.each(this.barItems, function(v){
29972 if (!v.isActive()) {
29984 setActiveItem : function(item)
29988 Roo.each(this.barItems, function(v){
29989 if (v.rid == item.rid) {
29993 if (v.isActive()) {
29994 v.setActive(false);
29999 item.setActive(true);
30001 this.fireEvent('changed', this, item, prev);
30004 getBarItem: function(rid)
30008 Roo.each(this.barItems, function(e) {
30009 if (e.rid != rid) {
30020 indexOfItem : function(item)
30024 Roo.each(this.barItems, function(v, i){
30026 if (v.rid != item.rid) {
30037 setActiveNext : function()
30039 var i = this.indexOfItem(this.getActive());
30041 if (i > this.barItems.length) {
30045 this.setActiveItem(this.barItems[i+1]);
30048 setActivePrev : function()
30050 var i = this.indexOfItem(this.getActive());
30056 this.setActiveItem(this.barItems[i-1]);
30059 format : function()
30061 if(!this.barItems.length){
30065 var width = 100 / this.barItems.length;
30067 Roo.each(this.barItems, function(i){
30068 i.el.setStyle('width', width + '%');
30069 i.topEl.el.setStyle('width', width + '%');
30070 i.bottomEl.el.setStyle('width', width + '%');
30079 * Nav Progress Item
30084 * @class Roo.bootstrap.NavProgressItem
30085 * @extends Roo.bootstrap.Component
30086 * Bootstrap NavProgressItem class
30087 * @cfg {String} rid the reference id
30088 * @cfg {Boolean} active (true|false) Is item active default false
30089 * @cfg {Boolean} disabled (true|false) Is item active default false
30090 * @cfg {String} html
30091 * @cfg {String} position (top|bottom) text position default bottom
30092 * @cfg {String} icon show icon instead of number
30095 * Create a new NavProgressItem
30096 * @param {Object} config The config object
30098 Roo.bootstrap.NavProgressItem = function(config){
30099 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30104 * The raw click event for the entire grid.
30105 * @param {Roo.bootstrap.NavProgressItem} this
30106 * @param {Roo.EventObject} e
30113 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30119 position : 'bottom',
30122 getAutoCreate : function()
30124 var iconCls = 'roo-navigation-bar-item-icon';
30126 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30130 cls: 'roo-navigation-bar-item',
30140 cfg.cls += ' active';
30143 cfg.cls += ' disabled';
30149 disable : function()
30151 this.setDisabled(true);
30154 enable : function()
30156 this.setDisabled(false);
30159 initEvents: function()
30161 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30163 this.iconEl.on('click', this.onClick, this);
30166 onClick : function(e)
30168 e.preventDefault();
30174 if(this.fireEvent('click', this, e) === false){
30178 this.parent().setActiveItem(this);
30181 isActive: function ()
30183 return this.active;
30186 setActive : function(state)
30188 if(this.active == state){
30192 this.active = state;
30195 this.el.addClass('active');
30199 this.el.removeClass('active');
30204 setDisabled : function(state)
30206 if(this.disabled == state){
30210 this.disabled = state;
30213 this.el.addClass('disabled');
30217 this.el.removeClass('disabled');
30220 tooltipEl : function()
30222 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30235 * @class Roo.bootstrap.FieldLabel
30236 * @extends Roo.bootstrap.Component
30237 * Bootstrap FieldLabel class
30238 * @cfg {String} html contents of the element
30239 * @cfg {String} tag tag of the element default label
30240 * @cfg {String} cls class of the element
30241 * @cfg {String} target label target
30242 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30243 * @cfg {String} invalidClass default "text-warning"
30244 * @cfg {String} validClass default "text-success"
30245 * @cfg {String} iconTooltip default "This field is required"
30246 * @cfg {String} indicatorpos (left|right) default left
30249 * Create a new FieldLabel
30250 * @param {Object} config The config object
30253 Roo.bootstrap.FieldLabel = function(config){
30254 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30259 * Fires after the field has been marked as invalid.
30260 * @param {Roo.form.FieldLabel} this
30261 * @param {String} msg The validation message
30266 * Fires after the field has been validated with no errors.
30267 * @param {Roo.form.FieldLabel} this
30273 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30280 invalidClass : 'has-warning',
30281 validClass : 'has-success',
30282 iconTooltip : 'This field is required',
30283 indicatorpos : 'left',
30285 getAutoCreate : function(){
30288 if (!this.allowBlank) {
30294 cls : 'roo-bootstrap-field-label ' + this.cls,
30299 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30300 tooltip : this.iconTooltip
30309 if(this.indicatorpos == 'right'){
30312 cls : 'roo-bootstrap-field-label ' + this.cls,
30321 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30322 tooltip : this.iconTooltip
30331 initEvents: function()
30333 Roo.bootstrap.Element.superclass.initEvents.call(this);
30335 this.indicator = this.indicatorEl();
30337 if(this.indicator){
30338 this.indicator.removeClass('visible');
30339 this.indicator.addClass('invisible');
30342 Roo.bootstrap.FieldLabel.register(this);
30345 indicatorEl : function()
30347 var indicator = this.el.select('i.roo-required-indicator',true).first();
30358 * Mark this field as valid
30360 markValid : function()
30362 if(this.indicator){
30363 this.indicator.removeClass('visible');
30364 this.indicator.addClass('invisible');
30367 this.el.removeClass(this.invalidClass);
30369 this.el.addClass(this.validClass);
30371 this.fireEvent('valid', this);
30375 * Mark this field as invalid
30376 * @param {String} msg The validation message
30378 markInvalid : function(msg)
30380 if(this.indicator){
30381 this.indicator.removeClass('invisible');
30382 this.indicator.addClass('visible');
30385 this.el.removeClass(this.validClass);
30387 this.el.addClass(this.invalidClass);
30389 this.fireEvent('invalid', this, msg);
30395 Roo.apply(Roo.bootstrap.FieldLabel, {
30400 * register a FieldLabel Group
30401 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30403 register : function(label)
30405 if(this.groups.hasOwnProperty(label.target)){
30409 this.groups[label.target] = label;
30413 * fetch a FieldLabel Group based on the target
30414 * @param {string} target
30415 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30417 get: function(target) {
30418 if (typeof(this.groups[target]) == 'undefined') {
30422 return this.groups[target] ;
30431 * page DateSplitField.
30437 * @class Roo.bootstrap.DateSplitField
30438 * @extends Roo.bootstrap.Component
30439 * Bootstrap DateSplitField class
30440 * @cfg {string} fieldLabel - the label associated
30441 * @cfg {Number} labelWidth set the width of label (0-12)
30442 * @cfg {String} labelAlign (top|left)
30443 * @cfg {Boolean} dayAllowBlank (true|false) default false
30444 * @cfg {Boolean} monthAllowBlank (true|false) default false
30445 * @cfg {Boolean} yearAllowBlank (true|false) default false
30446 * @cfg {string} dayPlaceholder
30447 * @cfg {string} monthPlaceholder
30448 * @cfg {string} yearPlaceholder
30449 * @cfg {string} dayFormat default 'd'
30450 * @cfg {string} monthFormat default 'm'
30451 * @cfg {string} yearFormat default 'Y'
30452 * @cfg {Number} labellg set the width of label (1-12)
30453 * @cfg {Number} labelmd set the width of label (1-12)
30454 * @cfg {Number} labelsm set the width of label (1-12)
30455 * @cfg {Number} labelxs set the width of label (1-12)
30459 * Create a new DateSplitField
30460 * @param {Object} config The config object
30463 Roo.bootstrap.DateSplitField = function(config){
30464 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30470 * getting the data of years
30471 * @param {Roo.bootstrap.DateSplitField} this
30472 * @param {Object} years
30477 * getting the data of days
30478 * @param {Roo.bootstrap.DateSplitField} this
30479 * @param {Object} days
30484 * Fires after the field has been marked as invalid.
30485 * @param {Roo.form.Field} this
30486 * @param {String} msg The validation message
30491 * Fires after the field has been validated with no errors.
30492 * @param {Roo.form.Field} this
30498 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30501 labelAlign : 'top',
30503 dayAllowBlank : false,
30504 monthAllowBlank : false,
30505 yearAllowBlank : false,
30506 dayPlaceholder : '',
30507 monthPlaceholder : '',
30508 yearPlaceholder : '',
30512 isFormField : true,
30518 getAutoCreate : function()
30522 cls : 'row roo-date-split-field-group',
30527 cls : 'form-hidden-field roo-date-split-field-group-value',
30533 var labelCls = 'col-md-12';
30534 var contentCls = 'col-md-4';
30536 if(this.fieldLabel){
30540 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30544 html : this.fieldLabel
30549 if(this.labelAlign == 'left'){
30551 if(this.labelWidth > 12){
30552 label.style = "width: " + this.labelWidth + 'px';
30555 if(this.labelWidth < 13 && this.labelmd == 0){
30556 this.labelmd = this.labelWidth;
30559 if(this.labellg > 0){
30560 labelCls = ' col-lg-' + this.labellg;
30561 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30564 if(this.labelmd > 0){
30565 labelCls = ' col-md-' + this.labelmd;
30566 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30569 if(this.labelsm > 0){
30570 labelCls = ' col-sm-' + this.labelsm;
30571 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30574 if(this.labelxs > 0){
30575 labelCls = ' col-xs-' + this.labelxs;
30576 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30580 label.cls += ' ' + labelCls;
30582 cfg.cn.push(label);
30585 Roo.each(['day', 'month', 'year'], function(t){
30588 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30595 inputEl: function ()
30597 return this.el.select('.roo-date-split-field-group-value', true).first();
30600 onRender : function(ct, position)
30604 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30606 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30608 this.dayField = new Roo.bootstrap.ComboBox({
30609 allowBlank : this.dayAllowBlank,
30610 alwaysQuery : true,
30611 displayField : 'value',
30614 forceSelection : true,
30616 placeholder : this.dayPlaceholder,
30617 selectOnFocus : true,
30618 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30619 triggerAction : 'all',
30621 valueField : 'value',
30622 store : new Roo.data.SimpleStore({
30623 data : (function() {
30625 _this.fireEvent('days', _this, days);
30628 fields : [ 'value' ]
30631 select : function (_self, record, index)
30633 _this.setValue(_this.getValue());
30638 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30640 this.monthField = new Roo.bootstrap.MonthField({
30641 after : '<i class=\"fa fa-calendar\"></i>',
30642 allowBlank : this.monthAllowBlank,
30643 placeholder : this.monthPlaceholder,
30646 render : function (_self)
30648 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30649 e.preventDefault();
30653 select : function (_self, oldvalue, newvalue)
30655 _this.setValue(_this.getValue());
30660 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30662 this.yearField = new Roo.bootstrap.ComboBox({
30663 allowBlank : this.yearAllowBlank,
30664 alwaysQuery : true,
30665 displayField : 'value',
30668 forceSelection : true,
30670 placeholder : this.yearPlaceholder,
30671 selectOnFocus : true,
30672 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30673 triggerAction : 'all',
30675 valueField : 'value',
30676 store : new Roo.data.SimpleStore({
30677 data : (function() {
30679 _this.fireEvent('years', _this, years);
30682 fields : [ 'value' ]
30685 select : function (_self, record, index)
30687 _this.setValue(_this.getValue());
30692 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30695 setValue : function(v, format)
30697 this.inputEl.dom.value = v;
30699 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30701 var d = Date.parseDate(v, f);
30708 this.setDay(d.format(this.dayFormat));
30709 this.setMonth(d.format(this.monthFormat));
30710 this.setYear(d.format(this.yearFormat));
30717 setDay : function(v)
30719 this.dayField.setValue(v);
30720 this.inputEl.dom.value = this.getValue();
30725 setMonth : function(v)
30727 this.monthField.setValue(v, true);
30728 this.inputEl.dom.value = this.getValue();
30733 setYear : function(v)
30735 this.yearField.setValue(v);
30736 this.inputEl.dom.value = this.getValue();
30741 getDay : function()
30743 return this.dayField.getValue();
30746 getMonth : function()
30748 return this.monthField.getValue();
30751 getYear : function()
30753 return this.yearField.getValue();
30756 getValue : function()
30758 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30760 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30770 this.inputEl.dom.value = '';
30775 validate : function()
30777 var d = this.dayField.validate();
30778 var m = this.monthField.validate();
30779 var y = this.yearField.validate();
30784 (!this.dayAllowBlank && !d) ||
30785 (!this.monthAllowBlank && !m) ||
30786 (!this.yearAllowBlank && !y)
30791 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30800 this.markInvalid();
30805 markValid : function()
30808 var label = this.el.select('label', true).first();
30809 var icon = this.el.select('i.fa-star', true).first();
30815 this.fireEvent('valid', this);
30819 * Mark this field as invalid
30820 * @param {String} msg The validation message
30822 markInvalid : function(msg)
30825 var label = this.el.select('label', true).first();
30826 var icon = this.el.select('i.fa-star', true).first();
30828 if(label && !icon){
30829 this.el.select('.roo-date-split-field-label', true).createChild({
30831 cls : 'text-danger fa fa-lg fa-star',
30832 tooltip : 'This field is required',
30833 style : 'margin-right:5px;'
30837 this.fireEvent('invalid', this, msg);
30840 clearInvalid : function()
30842 var label = this.el.select('label', true).first();
30843 var icon = this.el.select('i.fa-star', true).first();
30849 this.fireEvent('valid', this);
30852 getName: function()
30862 * http://masonry.desandro.com
30864 * The idea is to render all the bricks based on vertical width...
30866 * The original code extends 'outlayer' - we might need to use that....
30872 * @class Roo.bootstrap.LayoutMasonry
30873 * @extends Roo.bootstrap.Component
30874 * Bootstrap Layout Masonry class
30877 * Create a new Element
30878 * @param {Object} config The config object
30881 Roo.bootstrap.LayoutMasonry = function(config){
30883 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30887 Roo.bootstrap.LayoutMasonry.register(this);
30893 * Fire after layout the items
30894 * @param {Roo.bootstrap.LayoutMasonry} this
30895 * @param {Roo.EventObject} e
30902 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30905 * @cfg {Boolean} isLayoutInstant = no animation?
30907 isLayoutInstant : false, // needed?
30910 * @cfg {Number} boxWidth width of the columns
30915 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30920 * @cfg {Number} padWidth padding below box..
30925 * @cfg {Number} gutter gutter width..
30930 * @cfg {Number} maxCols maximum number of columns
30936 * @cfg {Boolean} isAutoInitial defalut true
30938 isAutoInitial : true,
30943 * @cfg {Boolean} isHorizontal defalut false
30945 isHorizontal : false,
30947 currentSize : null,
30953 bricks: null, //CompositeElement
30957 _isLayoutInited : false,
30959 // isAlternative : false, // only use for vertical layout...
30962 * @cfg {Number} alternativePadWidth padding below box..
30964 alternativePadWidth : 50,
30966 selectedBrick : [],
30968 getAutoCreate : function(){
30970 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30974 cls: 'blog-masonary-wrapper ' + this.cls,
30976 cls : 'mas-boxes masonary'
30983 getChildContainer: function( )
30985 if (this.boxesEl) {
30986 return this.boxesEl;
30989 this.boxesEl = this.el.select('.mas-boxes').first();
30991 return this.boxesEl;
30995 initEvents : function()
30999 if(this.isAutoInitial){
31000 Roo.log('hook children rendered');
31001 this.on('childrenrendered', function() {
31002 Roo.log('children rendered');
31008 initial : function()
31010 this.selectedBrick = [];
31012 this.currentSize = this.el.getBox(true);
31014 Roo.EventManager.onWindowResize(this.resize, this);
31016 if(!this.isAutoInitial){
31024 //this.layout.defer(500,this);
31028 resize : function()
31030 var cs = this.el.getBox(true);
31033 this.currentSize.width == cs.width &&
31034 this.currentSize.x == cs.x &&
31035 this.currentSize.height == cs.height &&
31036 this.currentSize.y == cs.y
31038 Roo.log("no change in with or X or Y");
31042 this.currentSize = cs;
31048 layout : function()
31050 this._resetLayout();
31052 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31054 this.layoutItems( isInstant );
31056 this._isLayoutInited = true;
31058 this.fireEvent('layout', this);
31062 _resetLayout : function()
31064 if(this.isHorizontal){
31065 this.horizontalMeasureColumns();
31069 this.verticalMeasureColumns();
31073 verticalMeasureColumns : function()
31075 this.getContainerWidth();
31077 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31078 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31082 var boxWidth = this.boxWidth + this.padWidth;
31084 if(this.containerWidth < this.boxWidth){
31085 boxWidth = this.containerWidth
31088 var containerWidth = this.containerWidth;
31090 var cols = Math.floor(containerWidth / boxWidth);
31092 this.cols = Math.max( cols, 1 );
31094 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31096 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31098 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31100 this.colWidth = boxWidth + avail - this.padWidth;
31102 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31103 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31106 horizontalMeasureColumns : function()
31108 this.getContainerWidth();
31110 var boxWidth = this.boxWidth;
31112 if(this.containerWidth < boxWidth){
31113 boxWidth = this.containerWidth;
31116 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31118 this.el.setHeight(boxWidth);
31122 getContainerWidth : function()
31124 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31127 layoutItems : function( isInstant )
31129 Roo.log(this.bricks);
31131 var items = Roo.apply([], this.bricks);
31133 if(this.isHorizontal){
31134 this._horizontalLayoutItems( items , isInstant );
31138 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31139 // this._verticalAlternativeLayoutItems( items , isInstant );
31143 this._verticalLayoutItems( items , isInstant );
31147 _verticalLayoutItems : function ( items , isInstant)
31149 if ( !items || !items.length ) {
31154 ['xs', 'xs', 'xs', 'tall'],
31155 ['xs', 'xs', 'tall'],
31156 ['xs', 'xs', 'sm'],
31157 ['xs', 'xs', 'xs'],
31163 ['sm', 'xs', 'xs'],
31167 ['tall', 'xs', 'xs', 'xs'],
31168 ['tall', 'xs', 'xs'],
31180 Roo.each(items, function(item, k){
31182 switch (item.size) {
31183 // these layouts take up a full box,
31194 boxes.push([item]);
31217 var filterPattern = function(box, length)
31225 var pattern = box.slice(0, length);
31229 Roo.each(pattern, function(i){
31230 format.push(i.size);
31233 Roo.each(standard, function(s){
31235 if(String(s) != String(format)){
31244 if(!match && length == 1){
31249 filterPattern(box, length - 1);
31253 queue.push(pattern);
31255 box = box.slice(length, box.length);
31257 filterPattern(box, 4);
31263 Roo.each(boxes, function(box, k){
31269 if(box.length == 1){
31274 filterPattern(box, 4);
31278 this._processVerticalLayoutQueue( queue, isInstant );
31282 // _verticalAlternativeLayoutItems : function( items , isInstant )
31284 // if ( !items || !items.length ) {
31288 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31292 _horizontalLayoutItems : function ( items , isInstant)
31294 if ( !items || !items.length || items.length < 3) {
31300 var eItems = items.slice(0, 3);
31302 items = items.slice(3, items.length);
31305 ['xs', 'xs', 'xs', 'wide'],
31306 ['xs', 'xs', 'wide'],
31307 ['xs', 'xs', 'sm'],
31308 ['xs', 'xs', 'xs'],
31314 ['sm', 'xs', 'xs'],
31318 ['wide', 'xs', 'xs', 'xs'],
31319 ['wide', 'xs', 'xs'],
31332 Roo.each(items, function(item, k){
31334 switch (item.size) {
31345 boxes.push([item]);
31369 var filterPattern = function(box, length)
31377 var pattern = box.slice(0, length);
31381 Roo.each(pattern, function(i){
31382 format.push(i.size);
31385 Roo.each(standard, function(s){
31387 if(String(s) != String(format)){
31396 if(!match && length == 1){
31401 filterPattern(box, length - 1);
31405 queue.push(pattern);
31407 box = box.slice(length, box.length);
31409 filterPattern(box, 4);
31415 Roo.each(boxes, function(box, k){
31421 if(box.length == 1){
31426 filterPattern(box, 4);
31433 var pos = this.el.getBox(true);
31437 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31439 var hit_end = false;
31441 Roo.each(queue, function(box){
31445 Roo.each(box, function(b){
31447 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31457 Roo.each(box, function(b){
31459 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31462 mx = Math.max(mx, b.x);
31466 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31470 Roo.each(box, function(b){
31472 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31486 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31489 /** Sets position of item in DOM
31490 * @param {Element} item
31491 * @param {Number} x - horizontal position
31492 * @param {Number} y - vertical position
31493 * @param {Boolean} isInstant - disables transitions
31495 _processVerticalLayoutQueue : function( queue, isInstant )
31497 var pos = this.el.getBox(true);
31502 for (var i = 0; i < this.cols; i++){
31506 Roo.each(queue, function(box, k){
31508 var col = k % this.cols;
31510 Roo.each(box, function(b,kk){
31512 b.el.position('absolute');
31514 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31515 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31517 if(b.size == 'md-left' || b.size == 'md-right'){
31518 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31519 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31522 b.el.setWidth(width);
31523 b.el.setHeight(height);
31525 b.el.select('iframe',true).setSize(width,height);
31529 for (var i = 0; i < this.cols; i++){
31531 if(maxY[i] < maxY[col]){
31536 col = Math.min(col, i);
31540 x = pos.x + col * (this.colWidth + this.padWidth);
31544 var positions = [];
31546 switch (box.length){
31548 positions = this.getVerticalOneBoxColPositions(x, y, box);
31551 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31554 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31557 positions = this.getVerticalFourBoxColPositions(x, y, box);
31563 Roo.each(box, function(b,kk){
31565 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31567 var sz = b.el.getSize();
31569 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31577 for (var i = 0; i < this.cols; i++){
31578 mY = Math.max(mY, maxY[i]);
31581 this.el.setHeight(mY - pos.y);
31585 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31587 // var pos = this.el.getBox(true);
31590 // var maxX = pos.right;
31592 // var maxHeight = 0;
31594 // Roo.each(items, function(item, k){
31598 // item.el.position('absolute');
31600 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31602 // item.el.setWidth(width);
31604 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31606 // item.el.setHeight(height);
31609 // item.el.setXY([x, y], isInstant ? false : true);
31611 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31614 // y = y + height + this.alternativePadWidth;
31616 // maxHeight = maxHeight + height + this.alternativePadWidth;
31620 // this.el.setHeight(maxHeight);
31624 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31626 var pos = this.el.getBox(true);
31631 var maxX = pos.right;
31633 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31635 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31637 Roo.each(queue, function(box, k){
31639 Roo.each(box, function(b, kk){
31641 b.el.position('absolute');
31643 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31644 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31646 if(b.size == 'md-left' || b.size == 'md-right'){
31647 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31648 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31651 b.el.setWidth(width);
31652 b.el.setHeight(height);
31660 var positions = [];
31662 switch (box.length){
31664 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31667 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31670 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31673 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31679 Roo.each(box, function(b,kk){
31681 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31683 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31691 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31693 Roo.each(eItems, function(b,k){
31695 b.size = (k == 0) ? 'sm' : 'xs';
31696 b.x = (k == 0) ? 2 : 1;
31697 b.y = (k == 0) ? 2 : 1;
31699 b.el.position('absolute');
31701 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31703 b.el.setWidth(width);
31705 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31707 b.el.setHeight(height);
31711 var positions = [];
31714 x : maxX - this.unitWidth * 2 - this.gutter,
31719 x : maxX - this.unitWidth,
31720 y : minY + (this.unitWidth + this.gutter) * 2
31724 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31728 Roo.each(eItems, function(b,k){
31730 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31736 getVerticalOneBoxColPositions : function(x, y, box)
31740 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31742 if(box[0].size == 'md-left'){
31746 if(box[0].size == 'md-right'){
31751 x : x + (this.unitWidth + this.gutter) * rand,
31758 getVerticalTwoBoxColPositions : function(x, y, box)
31762 if(box[0].size == 'xs'){
31766 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31770 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31784 x : x + (this.unitWidth + this.gutter) * 2,
31785 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31792 getVerticalThreeBoxColPositions : function(x, y, box)
31796 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31804 x : x + (this.unitWidth + this.gutter) * 1,
31809 x : x + (this.unitWidth + this.gutter) * 2,
31817 if(box[0].size == 'xs' && box[1].size == 'xs'){
31826 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31830 x : x + (this.unitWidth + this.gutter) * 1,
31844 x : x + (this.unitWidth + this.gutter) * 2,
31849 x : x + (this.unitWidth + this.gutter) * 2,
31850 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31857 getVerticalFourBoxColPositions : function(x, y, box)
31861 if(box[0].size == 'xs'){
31870 y : y + (this.unitHeight + this.gutter) * 1
31875 y : y + (this.unitHeight + this.gutter) * 2
31879 x : x + (this.unitWidth + this.gutter) * 1,
31893 x : x + (this.unitWidth + this.gutter) * 2,
31898 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31899 y : y + (this.unitHeight + this.gutter) * 1
31903 x : x + (this.unitWidth + this.gutter) * 2,
31904 y : y + (this.unitWidth + this.gutter) * 2
31911 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31915 if(box[0].size == 'md-left'){
31917 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31924 if(box[0].size == 'md-right'){
31926 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31927 y : minY + (this.unitWidth + this.gutter) * 1
31933 var rand = Math.floor(Math.random() * (4 - box[0].y));
31936 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31937 y : minY + (this.unitWidth + this.gutter) * rand
31944 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31948 if(box[0].size == 'xs'){
31951 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31956 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31957 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31965 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31970 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31971 y : minY + (this.unitWidth + this.gutter) * 2
31978 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31982 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31985 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31990 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31991 y : minY + (this.unitWidth + this.gutter) * 1
31995 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31996 y : minY + (this.unitWidth + this.gutter) * 2
32003 if(box[0].size == 'xs' && box[1].size == 'xs'){
32006 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32011 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32016 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32017 y : minY + (this.unitWidth + this.gutter) * 1
32025 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32030 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32031 y : minY + (this.unitWidth + this.gutter) * 2
32035 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32036 y : minY + (this.unitWidth + this.gutter) * 2
32043 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32047 if(box[0].size == 'xs'){
32050 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32055 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32060 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),
32065 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32066 y : minY + (this.unitWidth + this.gutter) * 1
32074 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32079 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32080 y : minY + (this.unitWidth + this.gutter) * 2
32084 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32085 y : minY + (this.unitWidth + this.gutter) * 2
32089 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),
32090 y : minY + (this.unitWidth + this.gutter) * 2
32098 * remove a Masonry Brick
32099 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32101 removeBrick : function(brick_id)
32107 for (var i = 0; i<this.bricks.length; i++) {
32108 if (this.bricks[i].id == brick_id) {
32109 this.bricks.splice(i,1);
32110 this.el.dom.removeChild(Roo.get(brick_id).dom);
32117 * adds a Masonry Brick
32118 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32120 addBrick : function(cfg)
32122 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32123 //this.register(cn);
32124 cn.parentId = this.id;
32125 cn.render(this.el);
32130 * register a Masonry Brick
32131 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32134 register : function(brick)
32136 this.bricks.push(brick);
32137 brick.masonryId = this.id;
32141 * clear all the Masonry Brick
32143 clearAll : function()
32146 //this.getChildContainer().dom.innerHTML = "";
32147 this.el.dom.innerHTML = '';
32150 getSelected : function()
32152 if (!this.selectedBrick) {
32156 return this.selectedBrick;
32160 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32164 * register a Masonry Layout
32165 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32168 register : function(layout)
32170 this.groups[layout.id] = layout;
32173 * fetch a Masonry Layout based on the masonry layout ID
32174 * @param {string} the masonry layout to add
32175 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32178 get: function(layout_id) {
32179 if (typeof(this.groups[layout_id]) == 'undefined') {
32182 return this.groups[layout_id] ;
32194 * http://masonry.desandro.com
32196 * The idea is to render all the bricks based on vertical width...
32198 * The original code extends 'outlayer' - we might need to use that....
32204 * @class Roo.bootstrap.LayoutMasonryAuto
32205 * @extends Roo.bootstrap.Component
32206 * Bootstrap Layout Masonry class
32209 * Create a new Element
32210 * @param {Object} config The config object
32213 Roo.bootstrap.LayoutMasonryAuto = function(config){
32214 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32217 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32220 * @cfg {Boolean} isFitWidth - resize the width..
32222 isFitWidth : false, // options..
32224 * @cfg {Boolean} isOriginLeft = left align?
32226 isOriginLeft : true,
32228 * @cfg {Boolean} isOriginTop = top align?
32230 isOriginTop : false,
32232 * @cfg {Boolean} isLayoutInstant = no animation?
32234 isLayoutInstant : false, // needed?
32236 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32238 isResizingContainer : true,
32240 * @cfg {Number} columnWidth width of the columns
32246 * @cfg {Number} maxCols maximum number of columns
32251 * @cfg {Number} padHeight padding below box..
32257 * @cfg {Boolean} isAutoInitial defalut true
32260 isAutoInitial : true,
32266 initialColumnWidth : 0,
32267 currentSize : null,
32269 colYs : null, // array.
32276 bricks: null, //CompositeElement
32277 cols : 0, // array?
32278 // element : null, // wrapped now this.el
32279 _isLayoutInited : null,
32282 getAutoCreate : function(){
32286 cls: 'blog-masonary-wrapper ' + this.cls,
32288 cls : 'mas-boxes masonary'
32295 getChildContainer: function( )
32297 if (this.boxesEl) {
32298 return this.boxesEl;
32301 this.boxesEl = this.el.select('.mas-boxes').first();
32303 return this.boxesEl;
32307 initEvents : function()
32311 if(this.isAutoInitial){
32312 Roo.log('hook children rendered');
32313 this.on('childrenrendered', function() {
32314 Roo.log('children rendered');
32321 initial : function()
32323 this.reloadItems();
32325 this.currentSize = this.el.getBox(true);
32327 /// was window resize... - let's see if this works..
32328 Roo.EventManager.onWindowResize(this.resize, this);
32330 if(!this.isAutoInitial){
32335 this.layout.defer(500,this);
32338 reloadItems: function()
32340 this.bricks = this.el.select('.masonry-brick', true);
32342 this.bricks.each(function(b) {
32343 //Roo.log(b.getSize());
32344 if (!b.attr('originalwidth')) {
32345 b.attr('originalwidth', b.getSize().width);
32350 Roo.log(this.bricks.elements.length);
32353 resize : function()
32356 var cs = this.el.getBox(true);
32358 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32359 Roo.log("no change in with or X");
32362 this.currentSize = cs;
32366 layout : function()
32369 this._resetLayout();
32370 //this._manageStamps();
32372 // don't animate first layout
32373 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32374 this.layoutItems( isInstant );
32376 // flag for initalized
32377 this._isLayoutInited = true;
32380 layoutItems : function( isInstant )
32382 //var items = this._getItemsForLayout( this.items );
32383 // original code supports filtering layout items.. we just ignore it..
32385 this._layoutItems( this.bricks , isInstant );
32387 this._postLayout();
32389 _layoutItems : function ( items , isInstant)
32391 //this.fireEvent( 'layout', this, items );
32394 if ( !items || !items.elements.length ) {
32395 // no items, emit event with empty array
32400 items.each(function(item) {
32401 Roo.log("layout item");
32403 // get x/y object from method
32404 var position = this._getItemLayoutPosition( item );
32406 position.item = item;
32407 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32408 queue.push( position );
32411 this._processLayoutQueue( queue );
32413 /** Sets position of item in DOM
32414 * @param {Element} item
32415 * @param {Number} x - horizontal position
32416 * @param {Number} y - vertical position
32417 * @param {Boolean} isInstant - disables transitions
32419 _processLayoutQueue : function( queue )
32421 for ( var i=0, len = queue.length; i < len; i++ ) {
32422 var obj = queue[i];
32423 obj.item.position('absolute');
32424 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32430 * Any logic you want to do after each layout,
32431 * i.e. size the container
32433 _postLayout : function()
32435 this.resizeContainer();
32438 resizeContainer : function()
32440 if ( !this.isResizingContainer ) {
32443 var size = this._getContainerSize();
32445 this.el.setSize(size.width,size.height);
32446 this.boxesEl.setSize(size.width,size.height);
32452 _resetLayout : function()
32454 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32455 this.colWidth = this.el.getWidth();
32456 //this.gutter = this.el.getWidth();
32458 this.measureColumns();
32464 this.colYs.push( 0 );
32470 measureColumns : function()
32472 this.getContainerWidth();
32473 // if columnWidth is 0, default to outerWidth of first item
32474 if ( !this.columnWidth ) {
32475 var firstItem = this.bricks.first();
32476 Roo.log(firstItem);
32477 this.columnWidth = this.containerWidth;
32478 if (firstItem && firstItem.attr('originalwidth') ) {
32479 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32481 // columnWidth fall back to item of first element
32482 Roo.log("set column width?");
32483 this.initialColumnWidth = this.columnWidth ;
32485 // if first elem has no width, default to size of container
32490 if (this.initialColumnWidth) {
32491 this.columnWidth = this.initialColumnWidth;
32496 // column width is fixed at the top - however if container width get's smaller we should
32499 // this bit calcs how man columns..
32501 var columnWidth = this.columnWidth += this.gutter;
32503 // calculate columns
32504 var containerWidth = this.containerWidth + this.gutter;
32506 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32507 // fix rounding errors, typically with gutters
32508 var excess = columnWidth - containerWidth % columnWidth;
32511 // if overshoot is less than a pixel, round up, otherwise floor it
32512 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32513 cols = Math[ mathMethod ]( cols );
32514 this.cols = Math.max( cols, 1 );
32515 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32517 // padding positioning..
32518 var totalColWidth = this.cols * this.columnWidth;
32519 var padavail = this.containerWidth - totalColWidth;
32520 // so for 2 columns - we need 3 'pads'
32522 var padNeeded = (1+this.cols) * this.padWidth;
32524 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32526 this.columnWidth += padExtra
32527 //this.padWidth = Math.floor(padavail / ( this.cols));
32529 // adjust colum width so that padding is fixed??
32531 // we have 3 columns ... total = width * 3
32532 // we have X left over... that should be used by
32534 //if (this.expandC) {
32542 getContainerWidth : function()
32544 /* // container is parent if fit width
32545 var container = this.isFitWidth ? this.element.parentNode : this.element;
32546 // check that this.size and size are there
32547 // IE8 triggers resize on body size change, so they might not be
32549 var size = getSize( container ); //FIXME
32550 this.containerWidth = size && size.innerWidth; //FIXME
32553 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32557 _getItemLayoutPosition : function( item ) // what is item?
32559 // we resize the item to our columnWidth..
32561 item.setWidth(this.columnWidth);
32562 item.autoBoxAdjust = false;
32564 var sz = item.getSize();
32566 // how many columns does this brick span
32567 var remainder = this.containerWidth % this.columnWidth;
32569 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32570 // round if off by 1 pixel, otherwise use ceil
32571 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32572 colSpan = Math.min( colSpan, this.cols );
32574 // normally this should be '1' as we dont' currently allow multi width columns..
32576 var colGroup = this._getColGroup( colSpan );
32577 // get the minimum Y value from the columns
32578 var minimumY = Math.min.apply( Math, colGroup );
32579 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32581 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32583 // position the brick
32585 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32586 y: this.currentSize.y + minimumY + this.padHeight
32590 // apply setHeight to necessary columns
32591 var setHeight = minimumY + sz.height + this.padHeight;
32592 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32594 var setSpan = this.cols + 1 - colGroup.length;
32595 for ( var i = 0; i < setSpan; i++ ) {
32596 this.colYs[ shortColIndex + i ] = setHeight ;
32603 * @param {Number} colSpan - number of columns the element spans
32604 * @returns {Array} colGroup
32606 _getColGroup : function( colSpan )
32608 if ( colSpan < 2 ) {
32609 // if brick spans only one column, use all the column Ys
32614 // how many different places could this brick fit horizontally
32615 var groupCount = this.cols + 1 - colSpan;
32616 // for each group potential horizontal position
32617 for ( var i = 0; i < groupCount; i++ ) {
32618 // make an array of colY values for that one group
32619 var groupColYs = this.colYs.slice( i, i + colSpan );
32620 // and get the max value of the array
32621 colGroup[i] = Math.max.apply( Math, groupColYs );
32626 _manageStamp : function( stamp )
32628 var stampSize = stamp.getSize();
32629 var offset = stamp.getBox();
32630 // get the columns that this stamp affects
32631 var firstX = this.isOriginLeft ? offset.x : offset.right;
32632 var lastX = firstX + stampSize.width;
32633 var firstCol = Math.floor( firstX / this.columnWidth );
32634 firstCol = Math.max( 0, firstCol );
32636 var lastCol = Math.floor( lastX / this.columnWidth );
32637 // lastCol should not go over if multiple of columnWidth #425
32638 lastCol -= lastX % this.columnWidth ? 0 : 1;
32639 lastCol = Math.min( this.cols - 1, lastCol );
32641 // set colYs to bottom of the stamp
32642 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32645 for ( var i = firstCol; i <= lastCol; i++ ) {
32646 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32651 _getContainerSize : function()
32653 this.maxY = Math.max.apply( Math, this.colYs );
32658 if ( this.isFitWidth ) {
32659 size.width = this._getContainerFitWidth();
32665 _getContainerFitWidth : function()
32667 var unusedCols = 0;
32668 // count unused columns
32671 if ( this.colYs[i] !== 0 ) {
32676 // fit container to columns that have been used
32677 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32680 needsResizeLayout : function()
32682 var previousWidth = this.containerWidth;
32683 this.getContainerWidth();
32684 return previousWidth !== this.containerWidth;
32699 * @class Roo.bootstrap.MasonryBrick
32700 * @extends Roo.bootstrap.Component
32701 * Bootstrap MasonryBrick class
32704 * Create a new MasonryBrick
32705 * @param {Object} config The config object
32708 Roo.bootstrap.MasonryBrick = function(config){
32710 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32712 Roo.bootstrap.MasonryBrick.register(this);
32718 * When a MasonryBrick is clcik
32719 * @param {Roo.bootstrap.MasonryBrick} this
32720 * @param {Roo.EventObject} e
32726 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32729 * @cfg {String} title
32733 * @cfg {String} html
32737 * @cfg {String} bgimage
32741 * @cfg {String} videourl
32745 * @cfg {String} cls
32749 * @cfg {String} href
32753 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32758 * @cfg {String} placetitle (center|bottom)
32763 * @cfg {Boolean} isFitContainer defalut true
32765 isFitContainer : true,
32768 * @cfg {Boolean} preventDefault defalut false
32770 preventDefault : false,
32773 * @cfg {Boolean} inverse defalut false
32775 maskInverse : false,
32777 getAutoCreate : function()
32779 if(!this.isFitContainer){
32780 return this.getSplitAutoCreate();
32783 var cls = 'masonry-brick masonry-brick-full';
32785 if(this.href.length){
32786 cls += ' masonry-brick-link';
32789 if(this.bgimage.length){
32790 cls += ' masonry-brick-image';
32793 if(this.maskInverse){
32794 cls += ' mask-inverse';
32797 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32798 cls += ' enable-mask';
32802 cls += ' masonry-' + this.size + '-brick';
32805 if(this.placetitle.length){
32807 switch (this.placetitle) {
32809 cls += ' masonry-center-title';
32812 cls += ' masonry-bottom-title';
32819 if(!this.html.length && !this.bgimage.length){
32820 cls += ' masonry-center-title';
32823 if(!this.html.length && this.bgimage.length){
32824 cls += ' masonry-bottom-title';
32829 cls += ' ' + this.cls;
32833 tag: (this.href.length) ? 'a' : 'div',
32838 cls: 'masonry-brick-mask'
32842 cls: 'masonry-brick-paragraph',
32848 if(this.href.length){
32849 cfg.href = this.href;
32852 var cn = cfg.cn[1].cn;
32854 if(this.title.length){
32857 cls: 'masonry-brick-title',
32862 if(this.html.length){
32865 cls: 'masonry-brick-text',
32870 if (!this.title.length && !this.html.length) {
32871 cfg.cn[1].cls += ' hide';
32874 if(this.bgimage.length){
32877 cls: 'masonry-brick-image-view',
32882 if(this.videourl.length){
32883 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32884 // youtube support only?
32887 cls: 'masonry-brick-image-view',
32890 allowfullscreen : true
32898 getSplitAutoCreate : function()
32900 var cls = 'masonry-brick masonry-brick-split';
32902 if(this.href.length){
32903 cls += ' masonry-brick-link';
32906 if(this.bgimage.length){
32907 cls += ' masonry-brick-image';
32911 cls += ' masonry-' + this.size + '-brick';
32914 switch (this.placetitle) {
32916 cls += ' masonry-center-title';
32919 cls += ' masonry-bottom-title';
32922 if(!this.bgimage.length){
32923 cls += ' masonry-center-title';
32926 if(this.bgimage.length){
32927 cls += ' masonry-bottom-title';
32933 cls += ' ' + this.cls;
32937 tag: (this.href.length) ? 'a' : 'div',
32942 cls: 'masonry-brick-split-head',
32946 cls: 'masonry-brick-paragraph',
32953 cls: 'masonry-brick-split-body',
32959 if(this.href.length){
32960 cfg.href = this.href;
32963 if(this.title.length){
32964 cfg.cn[0].cn[0].cn.push({
32966 cls: 'masonry-brick-title',
32971 if(this.html.length){
32972 cfg.cn[1].cn.push({
32974 cls: 'masonry-brick-text',
32979 if(this.bgimage.length){
32980 cfg.cn[0].cn.push({
32982 cls: 'masonry-brick-image-view',
32987 if(this.videourl.length){
32988 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32989 // youtube support only?
32990 cfg.cn[0].cn.cn.push({
32992 cls: 'masonry-brick-image-view',
32995 allowfullscreen : true
33002 initEvents: function()
33004 switch (this.size) {
33037 this.el.on('touchstart', this.onTouchStart, this);
33038 this.el.on('touchmove', this.onTouchMove, this);
33039 this.el.on('touchend', this.onTouchEnd, this);
33040 this.el.on('contextmenu', this.onContextMenu, this);
33042 this.el.on('mouseenter' ,this.enter, this);
33043 this.el.on('mouseleave', this.leave, this);
33044 this.el.on('click', this.onClick, this);
33047 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33048 this.parent().bricks.push(this);
33053 onClick: function(e, el)
33055 var time = this.endTimer - this.startTimer;
33056 // Roo.log(e.preventDefault());
33059 e.preventDefault();
33064 if(!this.preventDefault){
33068 e.preventDefault();
33070 if (this.activeClass != '') {
33071 this.selectBrick();
33074 this.fireEvent('click', this, e);
33077 enter: function(e, el)
33079 e.preventDefault();
33081 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33085 if(this.bgimage.length && this.html.length){
33086 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33090 leave: function(e, el)
33092 e.preventDefault();
33094 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33098 if(this.bgimage.length && this.html.length){
33099 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33103 onTouchStart: function(e, el)
33105 // e.preventDefault();
33107 this.touchmoved = false;
33109 if(!this.isFitContainer){
33113 if(!this.bgimage.length || !this.html.length){
33117 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33119 this.timer = new Date().getTime();
33123 onTouchMove: function(e, el)
33125 this.touchmoved = true;
33128 onContextMenu : function(e,el)
33130 e.preventDefault();
33131 e.stopPropagation();
33135 onTouchEnd: function(e, el)
33137 // e.preventDefault();
33139 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33146 if(!this.bgimage.length || !this.html.length){
33148 if(this.href.length){
33149 window.location.href = this.href;
33155 if(!this.isFitContainer){
33159 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33161 window.location.href = this.href;
33164 //selection on single brick only
33165 selectBrick : function() {
33167 if (!this.parentId) {
33171 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33172 var index = m.selectedBrick.indexOf(this.id);
33175 m.selectedBrick.splice(index,1);
33176 this.el.removeClass(this.activeClass);
33180 for(var i = 0; i < m.selectedBrick.length; i++) {
33181 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33182 b.el.removeClass(b.activeClass);
33185 m.selectedBrick = [];
33187 m.selectedBrick.push(this.id);
33188 this.el.addClass(this.activeClass);
33192 isSelected : function(){
33193 return this.el.hasClass(this.activeClass);
33198 Roo.apply(Roo.bootstrap.MasonryBrick, {
33201 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33203 * register a Masonry Brick
33204 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33207 register : function(brick)
33209 //this.groups[brick.id] = brick;
33210 this.groups.add(brick.id, brick);
33213 * fetch a masonry brick based on the masonry brick ID
33214 * @param {string} the masonry brick to add
33215 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33218 get: function(brick_id)
33220 // if (typeof(this.groups[brick_id]) == 'undefined') {
33223 // return this.groups[brick_id] ;
33225 if(this.groups.key(brick_id)) {
33226 return this.groups.key(brick_id);
33244 * @class Roo.bootstrap.Brick
33245 * @extends Roo.bootstrap.Component
33246 * Bootstrap Brick class
33249 * Create a new Brick
33250 * @param {Object} config The config object
33253 Roo.bootstrap.Brick = function(config){
33254 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33260 * When a Brick is click
33261 * @param {Roo.bootstrap.Brick} this
33262 * @param {Roo.EventObject} e
33268 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33271 * @cfg {String} title
33275 * @cfg {String} html
33279 * @cfg {String} bgimage
33283 * @cfg {String} cls
33287 * @cfg {String} href
33291 * @cfg {String} video
33295 * @cfg {Boolean} square
33299 getAutoCreate : function()
33301 var cls = 'roo-brick';
33303 if(this.href.length){
33304 cls += ' roo-brick-link';
33307 if(this.bgimage.length){
33308 cls += ' roo-brick-image';
33311 if(!this.html.length && !this.bgimage.length){
33312 cls += ' roo-brick-center-title';
33315 if(!this.html.length && this.bgimage.length){
33316 cls += ' roo-brick-bottom-title';
33320 cls += ' ' + this.cls;
33324 tag: (this.href.length) ? 'a' : 'div',
33329 cls: 'roo-brick-paragraph',
33335 if(this.href.length){
33336 cfg.href = this.href;
33339 var cn = cfg.cn[0].cn;
33341 if(this.title.length){
33344 cls: 'roo-brick-title',
33349 if(this.html.length){
33352 cls: 'roo-brick-text',
33359 if(this.bgimage.length){
33362 cls: 'roo-brick-image-view',
33370 initEvents: function()
33372 if(this.title.length || this.html.length){
33373 this.el.on('mouseenter' ,this.enter, this);
33374 this.el.on('mouseleave', this.leave, this);
33377 Roo.EventManager.onWindowResize(this.resize, this);
33379 if(this.bgimage.length){
33380 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33381 this.imageEl.on('load', this.onImageLoad, this);
33388 onImageLoad : function()
33393 resize : function()
33395 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33397 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33399 if(this.bgimage.length){
33400 var image = this.el.select('.roo-brick-image-view', true).first();
33402 image.setWidth(paragraph.getWidth());
33405 image.setHeight(paragraph.getWidth());
33408 this.el.setHeight(image.getHeight());
33409 paragraph.setHeight(image.getHeight());
33415 enter: function(e, el)
33417 e.preventDefault();
33419 if(this.bgimage.length){
33420 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33421 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33425 leave: function(e, el)
33427 e.preventDefault();
33429 if(this.bgimage.length){
33430 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33431 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33446 * @class Roo.bootstrap.NumberField
33447 * @extends Roo.bootstrap.Input
33448 * Bootstrap NumberField class
33454 * Create a new NumberField
33455 * @param {Object} config The config object
33458 Roo.bootstrap.NumberField = function(config){
33459 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33462 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33465 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33467 allowDecimals : true,
33469 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33471 decimalSeparator : ".",
33473 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33475 decimalPrecision : 2,
33477 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33479 allowNegative : true,
33482 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33486 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33488 minValue : Number.NEGATIVE_INFINITY,
33490 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33492 maxValue : Number.MAX_VALUE,
33494 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33496 minText : "The minimum value for this field is {0}",
33498 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33500 maxText : "The maximum value for this field is {0}",
33502 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33503 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33505 nanText : "{0} is not a valid number",
33507 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33509 thousandsDelimiter : false,
33511 * @cfg {String} valueAlign alignment of value
33513 valueAlign : "left",
33515 getAutoCreate : function()
33517 var hiddenInput = {
33521 cls: 'hidden-number-input'
33525 hiddenInput.name = this.name;
33530 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33532 this.name = hiddenInput.name;
33534 if(cfg.cn.length > 0) {
33535 cfg.cn.push(hiddenInput);
33542 initEvents : function()
33544 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33546 var allowed = "0123456789";
33548 if(this.allowDecimals){
33549 allowed += this.decimalSeparator;
33552 if(this.allowNegative){
33556 if(this.thousandsDelimiter) {
33560 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33562 var keyPress = function(e){
33564 var k = e.getKey();
33566 var c = e.getCharCode();
33569 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33570 allowed.indexOf(String.fromCharCode(c)) === -1
33576 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33580 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33585 this.el.on("keypress", keyPress, this);
33588 validateValue : function(value)
33591 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33595 var num = this.parseValue(value);
33598 this.markInvalid(String.format(this.nanText, value));
33602 if(num < this.minValue){
33603 this.markInvalid(String.format(this.minText, this.minValue));
33607 if(num > this.maxValue){
33608 this.markInvalid(String.format(this.maxText, this.maxValue));
33615 getValue : function()
33617 var v = this.hiddenEl().getValue();
33619 return this.fixPrecision(this.parseValue(v));
33622 parseValue : function(value)
33624 if(this.thousandsDelimiter) {
33626 r = new RegExp(",", "g");
33627 value = value.replace(r, "");
33630 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33631 return isNaN(value) ? '' : value;
33634 fixPrecision : function(value)
33636 if(this.thousandsDelimiter) {
33638 r = new RegExp(",", "g");
33639 value = value.replace(r, "");
33642 var nan = isNaN(value);
33644 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33645 return nan ? '' : value;
33647 return parseFloat(value).toFixed(this.decimalPrecision);
33650 setValue : function(v)
33652 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33658 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33660 this.inputEl().dom.value = (v == '') ? '' :
33661 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33663 if(!this.allowZero && v === '0') {
33664 this.hiddenEl().dom.value = '';
33665 this.inputEl().dom.value = '';
33672 decimalPrecisionFcn : function(v)
33674 return Math.floor(v);
33677 beforeBlur : function()
33679 var v = this.parseValue(this.getRawValue());
33681 if(v || v === 0 || v === ''){
33686 hiddenEl : function()
33688 return this.el.select('input.hidden-number-input',true).first();
33700 * @class Roo.bootstrap.DocumentSlider
33701 * @extends Roo.bootstrap.Component
33702 * Bootstrap DocumentSlider class
33705 * Create a new DocumentViewer
33706 * @param {Object} config The config object
33709 Roo.bootstrap.DocumentSlider = function(config){
33710 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33717 * Fire after initEvent
33718 * @param {Roo.bootstrap.DocumentSlider} this
33723 * Fire after update
33724 * @param {Roo.bootstrap.DocumentSlider} this
33730 * @param {Roo.bootstrap.DocumentSlider} this
33736 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33742 getAutoCreate : function()
33746 cls : 'roo-document-slider',
33750 cls : 'roo-document-slider-header',
33754 cls : 'roo-document-slider-header-title'
33760 cls : 'roo-document-slider-body',
33764 cls : 'roo-document-slider-prev',
33768 cls : 'fa fa-chevron-left'
33774 cls : 'roo-document-slider-thumb',
33778 cls : 'roo-document-slider-image'
33784 cls : 'roo-document-slider-next',
33788 cls : 'fa fa-chevron-right'
33800 initEvents : function()
33802 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33803 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33805 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33806 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33808 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33809 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33811 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33812 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33814 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33815 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33817 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33818 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33820 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33821 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33823 this.thumbEl.on('click', this.onClick, this);
33825 this.prevIndicator.on('click', this.prev, this);
33827 this.nextIndicator.on('click', this.next, this);
33831 initial : function()
33833 if(this.files.length){
33834 this.indicator = 1;
33838 this.fireEvent('initial', this);
33841 update : function()
33843 this.imageEl.attr('src', this.files[this.indicator - 1]);
33845 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33847 this.prevIndicator.show();
33849 if(this.indicator == 1){
33850 this.prevIndicator.hide();
33853 this.nextIndicator.show();
33855 if(this.indicator == this.files.length){
33856 this.nextIndicator.hide();
33859 this.thumbEl.scrollTo('top');
33861 this.fireEvent('update', this);
33864 onClick : function(e)
33866 e.preventDefault();
33868 this.fireEvent('click', this);
33873 e.preventDefault();
33875 this.indicator = Math.max(1, this.indicator - 1);
33882 e.preventDefault();
33884 this.indicator = Math.min(this.files.length, this.indicator + 1);
33898 * @class Roo.bootstrap.RadioSet
33899 * @extends Roo.bootstrap.Input
33900 * Bootstrap RadioSet class
33901 * @cfg {String} indicatorpos (left|right) default left
33902 * @cfg {Boolean} inline (true|false) inline the element (default true)
33903 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33905 * Create a new RadioSet
33906 * @param {Object} config The config object
33909 Roo.bootstrap.RadioSet = function(config){
33911 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33915 Roo.bootstrap.RadioSet.register(this);
33920 * Fires when the element is checked or unchecked.
33921 * @param {Roo.bootstrap.RadioSet} this This radio
33922 * @param {Roo.bootstrap.Radio} item The checked item
33927 * Fires when the element is click.
33928 * @param {Roo.bootstrap.RadioSet} this This radio set
33929 * @param {Roo.bootstrap.Radio} item The checked item
33930 * @param {Roo.EventObject} e The event object
33937 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33945 indicatorpos : 'left',
33947 getAutoCreate : function()
33951 cls : 'roo-radio-set-label',
33955 html : this.fieldLabel
33960 if(this.indicatorpos == 'left'){
33963 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33964 tooltip : 'This field is required'
33969 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33970 tooltip : 'This field is required'
33976 cls : 'roo-radio-set-items'
33979 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33981 if (align === 'left' && this.fieldLabel.length) {
33984 cls : "roo-radio-set-right",
33990 if(this.labelWidth > 12){
33991 label.style = "width: " + this.labelWidth + 'px';
33994 if(this.labelWidth < 13 && this.labelmd == 0){
33995 this.labelmd = this.labelWidth;
33998 if(this.labellg > 0){
33999 label.cls += ' col-lg-' + this.labellg;
34000 items.cls += ' col-lg-' + (12 - this.labellg);
34003 if(this.labelmd > 0){
34004 label.cls += ' col-md-' + this.labelmd;
34005 items.cls += ' col-md-' + (12 - this.labelmd);
34008 if(this.labelsm > 0){
34009 label.cls += ' col-sm-' + this.labelsm;
34010 items.cls += ' col-sm-' + (12 - this.labelsm);
34013 if(this.labelxs > 0){
34014 label.cls += ' col-xs-' + this.labelxs;
34015 items.cls += ' col-xs-' + (12 - this.labelxs);
34021 cls : 'roo-radio-set',
34025 cls : 'roo-radio-set-input',
34028 value : this.value ? this.value : ''
34035 if(this.weight.length){
34036 cfg.cls += ' roo-radio-' + this.weight;
34040 cfg.cls += ' roo-radio-set-inline';
34044 ['xs','sm','md','lg'].map(function(size){
34045 if (settings[size]) {
34046 cfg.cls += ' col-' + size + '-' + settings[size];
34054 initEvents : function()
34056 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34057 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34059 if(!this.fieldLabel.length){
34060 this.labelEl.hide();
34063 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34064 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34066 this.indicator = this.indicatorEl();
34068 if(this.indicator){
34069 this.indicator.addClass('invisible');
34072 this.originalValue = this.getValue();
34076 inputEl: function ()
34078 return this.el.select('.roo-radio-set-input', true).first();
34081 getChildContainer : function()
34083 return this.itemsEl;
34086 register : function(item)
34088 this.radioes.push(item);
34092 validate : function()
34094 if(this.getVisibilityEl().hasClass('hidden')){
34100 Roo.each(this.radioes, function(i){
34109 if(this.allowBlank) {
34113 if(this.disabled || valid){
34118 this.markInvalid();
34123 markValid : function()
34125 if(this.labelEl.isVisible(true)){
34126 this.indicatorEl().removeClass('visible');
34127 this.indicatorEl().addClass('invisible');
34130 this.el.removeClass([this.invalidClass, this.validClass]);
34131 this.el.addClass(this.validClass);
34133 this.fireEvent('valid', this);
34136 markInvalid : function(msg)
34138 if(this.allowBlank || this.disabled){
34142 if(this.labelEl.isVisible(true)){
34143 this.indicatorEl().removeClass('invisible');
34144 this.indicatorEl().addClass('visible');
34147 this.el.removeClass([this.invalidClass, this.validClass]);
34148 this.el.addClass(this.invalidClass);
34150 this.fireEvent('invalid', this, msg);
34154 setValue : function(v, suppressEvent)
34156 if(this.value === v){
34163 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34166 Roo.each(this.radioes, function(i){
34168 i.el.removeClass('checked');
34171 Roo.each(this.radioes, function(i){
34173 if(i.value === v || i.value.toString() === v.toString()){
34175 i.el.addClass('checked');
34177 if(suppressEvent !== true){
34178 this.fireEvent('check', this, i);
34189 clearInvalid : function(){
34191 if(!this.el || this.preventMark){
34195 this.el.removeClass([this.invalidClass]);
34197 this.fireEvent('valid', this);
34202 Roo.apply(Roo.bootstrap.RadioSet, {
34206 register : function(set)
34208 this.groups[set.name] = set;
34211 get: function(name)
34213 if (typeof(this.groups[name]) == 'undefined') {
34217 return this.groups[name] ;
34223 * Ext JS Library 1.1.1
34224 * Copyright(c) 2006-2007, Ext JS, LLC.
34226 * Originally Released Under LGPL - original licence link has changed is not relivant.
34229 * <script type="text/javascript">
34234 * @class Roo.bootstrap.SplitBar
34235 * @extends Roo.util.Observable
34236 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34240 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34241 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34242 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34243 split.minSize = 100;
34244 split.maxSize = 600;
34245 split.animate = true;
34246 split.on('moved', splitterMoved);
34249 * Create a new SplitBar
34250 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34251 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34252 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34253 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34254 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34255 position of the SplitBar).
34257 Roo.bootstrap.SplitBar = function(cfg){
34262 // dragElement : elm
34263 // resizingElement: el,
34265 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34266 // placement : Roo.bootstrap.SplitBar.LEFT ,
34267 // existingProxy ???
34270 this.el = Roo.get(cfg.dragElement, true);
34271 this.el.dom.unselectable = "on";
34273 this.resizingEl = Roo.get(cfg.resizingElement, true);
34277 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34278 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34281 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34284 * The minimum size of the resizing element. (Defaults to 0)
34290 * The maximum size of the resizing element. (Defaults to 2000)
34293 this.maxSize = 2000;
34296 * Whether to animate the transition to the new size
34299 this.animate = false;
34302 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34305 this.useShim = false;
34310 if(!cfg.existingProxy){
34312 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34314 this.proxy = Roo.get(cfg.existingProxy).dom;
34317 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34320 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34323 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34326 this.dragSpecs = {};
34329 * @private The adapter to use to positon and resize elements
34331 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34332 this.adapter.init(this);
34334 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34336 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34337 this.el.addClass("roo-splitbar-h");
34340 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34341 this.el.addClass("roo-splitbar-v");
34347 * Fires when the splitter is moved (alias for {@link #event-moved})
34348 * @param {Roo.bootstrap.SplitBar} this
34349 * @param {Number} newSize the new width or height
34354 * Fires when the splitter is moved
34355 * @param {Roo.bootstrap.SplitBar} this
34356 * @param {Number} newSize the new width or height
34360 * @event beforeresize
34361 * Fires before the splitter is dragged
34362 * @param {Roo.bootstrap.SplitBar} this
34364 "beforeresize" : true,
34366 "beforeapply" : true
34369 Roo.util.Observable.call(this);
34372 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34373 onStartProxyDrag : function(x, y){
34374 this.fireEvent("beforeresize", this);
34376 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34378 o.enableDisplayMode("block");
34379 // all splitbars share the same overlay
34380 Roo.bootstrap.SplitBar.prototype.overlay = o;
34382 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34383 this.overlay.show();
34384 Roo.get(this.proxy).setDisplayed("block");
34385 var size = this.adapter.getElementSize(this);
34386 this.activeMinSize = this.getMinimumSize();;
34387 this.activeMaxSize = this.getMaximumSize();;
34388 var c1 = size - this.activeMinSize;
34389 var c2 = Math.max(this.activeMaxSize - size, 0);
34390 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34391 this.dd.resetConstraints();
34392 this.dd.setXConstraint(
34393 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34394 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34396 this.dd.setYConstraint(0, 0);
34398 this.dd.resetConstraints();
34399 this.dd.setXConstraint(0, 0);
34400 this.dd.setYConstraint(
34401 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34402 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34405 this.dragSpecs.startSize = size;
34406 this.dragSpecs.startPoint = [x, y];
34407 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34411 * @private Called after the drag operation by the DDProxy
34413 onEndProxyDrag : function(e){
34414 Roo.get(this.proxy).setDisplayed(false);
34415 var endPoint = Roo.lib.Event.getXY(e);
34417 this.overlay.hide();
34420 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34421 newSize = this.dragSpecs.startSize +
34422 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34423 endPoint[0] - this.dragSpecs.startPoint[0] :
34424 this.dragSpecs.startPoint[0] - endPoint[0]
34427 newSize = this.dragSpecs.startSize +
34428 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34429 endPoint[1] - this.dragSpecs.startPoint[1] :
34430 this.dragSpecs.startPoint[1] - endPoint[1]
34433 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34434 if(newSize != this.dragSpecs.startSize){
34435 if(this.fireEvent('beforeapply', this, newSize) !== false){
34436 this.adapter.setElementSize(this, newSize);
34437 this.fireEvent("moved", this, newSize);
34438 this.fireEvent("resize", this, newSize);
34444 * Get the adapter this SplitBar uses
34445 * @return The adapter object
34447 getAdapter : function(){
34448 return this.adapter;
34452 * Set the adapter this SplitBar uses
34453 * @param {Object} adapter A SplitBar adapter object
34455 setAdapter : function(adapter){
34456 this.adapter = adapter;
34457 this.adapter.init(this);
34461 * Gets the minimum size for the resizing element
34462 * @return {Number} The minimum size
34464 getMinimumSize : function(){
34465 return this.minSize;
34469 * Sets the minimum size for the resizing element
34470 * @param {Number} minSize The minimum size
34472 setMinimumSize : function(minSize){
34473 this.minSize = minSize;
34477 * Gets the maximum size for the resizing element
34478 * @return {Number} The maximum size
34480 getMaximumSize : function(){
34481 return this.maxSize;
34485 * Sets the maximum size for the resizing element
34486 * @param {Number} maxSize The maximum size
34488 setMaximumSize : function(maxSize){
34489 this.maxSize = maxSize;
34493 * Sets the initialize size for the resizing element
34494 * @param {Number} size The initial size
34496 setCurrentSize : function(size){
34497 var oldAnimate = this.animate;
34498 this.animate = false;
34499 this.adapter.setElementSize(this, size);
34500 this.animate = oldAnimate;
34504 * Destroy this splitbar.
34505 * @param {Boolean} removeEl True to remove the element
34507 destroy : function(removeEl){
34509 this.shim.remove();
34512 this.proxy.parentNode.removeChild(this.proxy);
34520 * @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.
34522 Roo.bootstrap.SplitBar.createProxy = function(dir){
34523 var proxy = new Roo.Element(document.createElement("div"));
34524 proxy.unselectable();
34525 var cls = 'roo-splitbar-proxy';
34526 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34527 document.body.appendChild(proxy.dom);
34532 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34533 * Default Adapter. It assumes the splitter and resizing element are not positioned
34534 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34536 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34539 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34540 // do nothing for now
34541 init : function(s){
34545 * Called before drag operations to get the current size of the resizing element.
34546 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34548 getElementSize : function(s){
34549 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34550 return s.resizingEl.getWidth();
34552 return s.resizingEl.getHeight();
34557 * Called after drag operations to set the size of the resizing element.
34558 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34559 * @param {Number} newSize The new size to set
34560 * @param {Function} onComplete A function to be invoked when resizing is complete
34562 setElementSize : function(s, newSize, onComplete){
34563 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34565 s.resizingEl.setWidth(newSize);
34567 onComplete(s, newSize);
34570 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34575 s.resizingEl.setHeight(newSize);
34577 onComplete(s, newSize);
34580 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34587 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34588 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34589 * Adapter that moves the splitter element to align with the resized sizing element.
34590 * Used with an absolute positioned SplitBar.
34591 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34592 * document.body, make sure you assign an id to the body element.
34594 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34595 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34596 this.container = Roo.get(container);
34599 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34600 init : function(s){
34601 this.basic.init(s);
34604 getElementSize : function(s){
34605 return this.basic.getElementSize(s);
34608 setElementSize : function(s, newSize, onComplete){
34609 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34612 moveSplitter : function(s){
34613 var yes = Roo.bootstrap.SplitBar;
34614 switch(s.placement){
34616 s.el.setX(s.resizingEl.getRight());
34619 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34622 s.el.setY(s.resizingEl.getBottom());
34625 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34632 * Orientation constant - Create a vertical SplitBar
34636 Roo.bootstrap.SplitBar.VERTICAL = 1;
34639 * Orientation constant - Create a horizontal SplitBar
34643 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34646 * Placement constant - The resizing element is to the left of the splitter element
34650 Roo.bootstrap.SplitBar.LEFT = 1;
34653 * Placement constant - The resizing element is to the right of the splitter element
34657 Roo.bootstrap.SplitBar.RIGHT = 2;
34660 * Placement constant - The resizing element is positioned above the splitter element
34664 Roo.bootstrap.SplitBar.TOP = 3;
34667 * Placement constant - The resizing element is positioned under splitter element
34671 Roo.bootstrap.SplitBar.BOTTOM = 4;
34672 Roo.namespace("Roo.bootstrap.layout");/*
34674 * Ext JS Library 1.1.1
34675 * Copyright(c) 2006-2007, Ext JS, LLC.
34677 * Originally Released Under LGPL - original licence link has changed is not relivant.
34680 * <script type="text/javascript">
34684 * @class Roo.bootstrap.layout.Manager
34685 * @extends Roo.bootstrap.Component
34686 * Base class for layout managers.
34688 Roo.bootstrap.layout.Manager = function(config)
34690 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34696 /** false to disable window resize monitoring @type Boolean */
34697 this.monitorWindowResize = true;
34702 * Fires when a layout is performed.
34703 * @param {Roo.LayoutManager} this
34707 * @event regionresized
34708 * Fires when the user resizes a region.
34709 * @param {Roo.LayoutRegion} region The resized region
34710 * @param {Number} newSize The new size (width for east/west, height for north/south)
34712 "regionresized" : true,
34714 * @event regioncollapsed
34715 * Fires when a region is collapsed.
34716 * @param {Roo.LayoutRegion} region The collapsed region
34718 "regioncollapsed" : true,
34720 * @event regionexpanded
34721 * Fires when a region is expanded.
34722 * @param {Roo.LayoutRegion} region The expanded region
34724 "regionexpanded" : true
34726 this.updating = false;
34729 this.el = Roo.get(config.el);
34735 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34740 monitorWindowResize : true,
34746 onRender : function(ct, position)
34749 this.el = Roo.get(ct);
34752 //this.fireEvent('render',this);
34756 initEvents: function()
34760 // ie scrollbar fix
34761 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34762 document.body.scroll = "no";
34763 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34764 this.el.position('relative');
34766 this.id = this.el.id;
34767 this.el.addClass("roo-layout-container");
34768 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34769 if(this.el.dom != document.body ) {
34770 this.el.on('resize', this.layout,this);
34771 this.el.on('show', this.layout,this);
34777 * Returns true if this layout is currently being updated
34778 * @return {Boolean}
34780 isUpdating : function(){
34781 return this.updating;
34785 * Suspend the LayoutManager from doing auto-layouts while
34786 * making multiple add or remove calls
34788 beginUpdate : function(){
34789 this.updating = true;
34793 * Restore auto-layouts and optionally disable the manager from performing a layout
34794 * @param {Boolean} noLayout true to disable a layout update
34796 endUpdate : function(noLayout){
34797 this.updating = false;
34803 layout: function(){
34807 onRegionResized : function(region, newSize){
34808 this.fireEvent("regionresized", region, newSize);
34812 onRegionCollapsed : function(region){
34813 this.fireEvent("regioncollapsed", region);
34816 onRegionExpanded : function(region){
34817 this.fireEvent("regionexpanded", region);
34821 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34822 * performs box-model adjustments.
34823 * @return {Object} The size as an object {width: (the width), height: (the height)}
34825 getViewSize : function()
34828 if(this.el.dom != document.body){
34829 size = this.el.getSize();
34831 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34833 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34834 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34839 * Returns the Element this layout is bound to.
34840 * @return {Roo.Element}
34842 getEl : function(){
34847 * Returns the specified region.
34848 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34849 * @return {Roo.LayoutRegion}
34851 getRegion : function(target){
34852 return this.regions[target.toLowerCase()];
34855 onWindowResize : function(){
34856 if(this.monitorWindowResize){
34863 * Ext JS Library 1.1.1
34864 * Copyright(c) 2006-2007, Ext JS, LLC.
34866 * Originally Released Under LGPL - original licence link has changed is not relivant.
34869 * <script type="text/javascript">
34872 * @class Roo.bootstrap.layout.Border
34873 * @extends Roo.bootstrap.layout.Manager
34874 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34875 * please see: examples/bootstrap/nested.html<br><br>
34877 <b>The container the layout is rendered into can be either the body element or any other element.
34878 If it is not the body element, the container needs to either be an absolute positioned element,
34879 or you will need to add "position:relative" to the css of the container. You will also need to specify
34880 the container size if it is not the body element.</b>
34883 * Create a new Border
34884 * @param {Object} config Configuration options
34886 Roo.bootstrap.layout.Border = function(config){
34887 config = config || {};
34888 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34892 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34893 if(config[region]){
34894 config[region].region = region;
34895 this.addRegion(config[region]);
34901 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34903 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34905 * Creates and adds a new region if it doesn't already exist.
34906 * @param {String} target The target region key (north, south, east, west or center).
34907 * @param {Object} config The regions config object
34908 * @return {BorderLayoutRegion} The new region
34910 addRegion : function(config)
34912 if(!this.regions[config.region]){
34913 var r = this.factory(config);
34914 this.bindRegion(r);
34916 return this.regions[config.region];
34920 bindRegion : function(r){
34921 this.regions[r.config.region] = r;
34923 r.on("visibilitychange", this.layout, this);
34924 r.on("paneladded", this.layout, this);
34925 r.on("panelremoved", this.layout, this);
34926 r.on("invalidated", this.layout, this);
34927 r.on("resized", this.onRegionResized, this);
34928 r.on("collapsed", this.onRegionCollapsed, this);
34929 r.on("expanded", this.onRegionExpanded, this);
34933 * Performs a layout update.
34935 layout : function()
34937 if(this.updating) {
34941 // render all the rebions if they have not been done alreayd?
34942 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34943 if(this.regions[region] && !this.regions[region].bodyEl){
34944 this.regions[region].onRender(this.el)
34948 var size = this.getViewSize();
34949 var w = size.width;
34950 var h = size.height;
34955 //var x = 0, y = 0;
34957 var rs = this.regions;
34958 var north = rs["north"];
34959 var south = rs["south"];
34960 var west = rs["west"];
34961 var east = rs["east"];
34962 var center = rs["center"];
34963 //if(this.hideOnLayout){ // not supported anymore
34964 //c.el.setStyle("display", "none");
34966 if(north && north.isVisible()){
34967 var b = north.getBox();
34968 var m = north.getMargins();
34969 b.width = w - (m.left+m.right);
34972 centerY = b.height + b.y + m.bottom;
34973 centerH -= centerY;
34974 north.updateBox(this.safeBox(b));
34976 if(south && south.isVisible()){
34977 var b = south.getBox();
34978 var m = south.getMargins();
34979 b.width = w - (m.left+m.right);
34981 var totalHeight = (b.height + m.top + m.bottom);
34982 b.y = h - totalHeight + m.top;
34983 centerH -= totalHeight;
34984 south.updateBox(this.safeBox(b));
34986 if(west && west.isVisible()){
34987 var b = west.getBox();
34988 var m = west.getMargins();
34989 b.height = centerH - (m.top+m.bottom);
34991 b.y = centerY + m.top;
34992 var totalWidth = (b.width + m.left + m.right);
34993 centerX += totalWidth;
34994 centerW -= totalWidth;
34995 west.updateBox(this.safeBox(b));
34997 if(east && east.isVisible()){
34998 var b = east.getBox();
34999 var m = east.getMargins();
35000 b.height = centerH - (m.top+m.bottom);
35001 var totalWidth = (b.width + m.left + m.right);
35002 b.x = w - totalWidth + m.left;
35003 b.y = centerY + m.top;
35004 centerW -= totalWidth;
35005 east.updateBox(this.safeBox(b));
35008 var m = center.getMargins();
35010 x: centerX + m.left,
35011 y: centerY + m.top,
35012 width: centerW - (m.left+m.right),
35013 height: centerH - (m.top+m.bottom)
35015 //if(this.hideOnLayout){
35016 //center.el.setStyle("display", "block");
35018 center.updateBox(this.safeBox(centerBox));
35021 this.fireEvent("layout", this);
35025 safeBox : function(box){
35026 box.width = Math.max(0, box.width);
35027 box.height = Math.max(0, box.height);
35032 * Adds a ContentPanel (or subclass) to this layout.
35033 * @param {String} target The target region key (north, south, east, west or center).
35034 * @param {Roo.ContentPanel} panel The panel to add
35035 * @return {Roo.ContentPanel} The added panel
35037 add : function(target, panel){
35039 target = target.toLowerCase();
35040 return this.regions[target].add(panel);
35044 * Remove a ContentPanel (or subclass) to this layout.
35045 * @param {String} target The target region key (north, south, east, west or center).
35046 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35047 * @return {Roo.ContentPanel} The removed panel
35049 remove : function(target, panel){
35050 target = target.toLowerCase();
35051 return this.regions[target].remove(panel);
35055 * Searches all regions for a panel with the specified id
35056 * @param {String} panelId
35057 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35059 findPanel : function(panelId){
35060 var rs = this.regions;
35061 for(var target in rs){
35062 if(typeof rs[target] != "function"){
35063 var p = rs[target].getPanel(panelId);
35073 * Searches all regions for a panel with the specified id and activates (shows) it.
35074 * @param {String/ContentPanel} panelId The panels id or the panel itself
35075 * @return {Roo.ContentPanel} The shown panel or null
35077 showPanel : function(panelId) {
35078 var rs = this.regions;
35079 for(var target in rs){
35080 var r = rs[target];
35081 if(typeof r != "function"){
35082 if(r.hasPanel(panelId)){
35083 return r.showPanel(panelId);
35091 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35092 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35095 restoreState : function(provider){
35097 provider = Roo.state.Manager;
35099 var sm = new Roo.LayoutStateManager();
35100 sm.init(this, provider);
35106 * Adds a xtype elements to the layout.
35110 xtype : 'ContentPanel',
35117 xtype : 'NestedLayoutPanel',
35123 items : [ ... list of content panels or nested layout panels.. ]
35127 * @param {Object} cfg Xtype definition of item to add.
35129 addxtype : function(cfg)
35131 // basically accepts a pannel...
35132 // can accept a layout region..!?!?
35133 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35136 // theory? children can only be panels??
35138 //if (!cfg.xtype.match(/Panel$/)) {
35143 if (typeof(cfg.region) == 'undefined') {
35144 Roo.log("Failed to add Panel, region was not set");
35148 var region = cfg.region;
35154 xitems = cfg.items;
35161 case 'Content': // ContentPanel (el, cfg)
35162 case 'Scroll': // ContentPanel (el, cfg)
35164 cfg.autoCreate = true;
35165 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35167 // var el = this.el.createChild();
35168 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35171 this.add(region, ret);
35175 case 'TreePanel': // our new panel!
35176 cfg.el = this.el.createChild();
35177 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35178 this.add(region, ret);
35183 // create a new Layout (which is a Border Layout...
35185 var clayout = cfg.layout;
35186 clayout.el = this.el.createChild();
35187 clayout.items = clayout.items || [];
35191 // replace this exitems with the clayout ones..
35192 xitems = clayout.items;
35194 // force background off if it's in center...
35195 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35196 cfg.background = false;
35198 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35201 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35202 //console.log('adding nested layout panel ' + cfg.toSource());
35203 this.add(region, ret);
35204 nb = {}; /// find first...
35209 // needs grid and region
35211 //var el = this.getRegion(region).el.createChild();
35213 *var el = this.el.createChild();
35214 // create the grid first...
35215 cfg.grid.container = el;
35216 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35219 if (region == 'center' && this.active ) {
35220 cfg.background = false;
35223 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35225 this.add(region, ret);
35227 if (cfg.background) {
35228 // render grid on panel activation (if panel background)
35229 ret.on('activate', function(gp) {
35230 if (!gp.grid.rendered) {
35231 // gp.grid.render(el);
35235 // cfg.grid.render(el);
35241 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35242 // it was the old xcomponent building that caused this before.
35243 // espeically if border is the top element in the tree.
35253 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35255 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35256 this.add(region, ret);
35260 throw "Can not add '" + cfg.xtype + "' to Border";
35266 this.beginUpdate();
35270 Roo.each(xitems, function(i) {
35271 region = nb && i.region ? i.region : false;
35273 var add = ret.addxtype(i);
35276 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35277 if (!i.background) {
35278 abn[region] = nb[region] ;
35285 // make the last non-background panel active..
35286 //if (nb) { Roo.log(abn); }
35289 for(var r in abn) {
35290 region = this.getRegion(r);
35292 // tried using nb[r], but it does not work..
35294 region.showPanel(abn[r]);
35305 factory : function(cfg)
35308 var validRegions = Roo.bootstrap.layout.Border.regions;
35310 var target = cfg.region;
35313 var r = Roo.bootstrap.layout;
35317 return new r.North(cfg);
35319 return new r.South(cfg);
35321 return new r.East(cfg);
35323 return new r.West(cfg);
35325 return new r.Center(cfg);
35327 throw 'Layout region "'+target+'" not supported.';
35334 * Ext JS Library 1.1.1
35335 * Copyright(c) 2006-2007, Ext JS, LLC.
35337 * Originally Released Under LGPL - original licence link has changed is not relivant.
35340 * <script type="text/javascript">
35344 * @class Roo.bootstrap.layout.Basic
35345 * @extends Roo.util.Observable
35346 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35347 * and does not have a titlebar, tabs or any other features. All it does is size and position
35348 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35349 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35350 * @cfg {string} region the region that it inhabits..
35351 * @cfg {bool} skipConfig skip config?
35355 Roo.bootstrap.layout.Basic = function(config){
35357 this.mgr = config.mgr;
35359 this.position = config.region;
35361 var skipConfig = config.skipConfig;
35365 * @scope Roo.BasicLayoutRegion
35369 * @event beforeremove
35370 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35371 * @param {Roo.LayoutRegion} this
35372 * @param {Roo.ContentPanel} panel The panel
35373 * @param {Object} e The cancel event object
35375 "beforeremove" : true,
35377 * @event invalidated
35378 * Fires when the layout for this region is changed.
35379 * @param {Roo.LayoutRegion} this
35381 "invalidated" : true,
35383 * @event visibilitychange
35384 * Fires when this region is shown or hidden
35385 * @param {Roo.LayoutRegion} this
35386 * @param {Boolean} visibility true or false
35388 "visibilitychange" : true,
35390 * @event paneladded
35391 * Fires when a panel is added.
35392 * @param {Roo.LayoutRegion} this
35393 * @param {Roo.ContentPanel} panel The panel
35395 "paneladded" : true,
35397 * @event panelremoved
35398 * Fires when a panel is removed.
35399 * @param {Roo.LayoutRegion} this
35400 * @param {Roo.ContentPanel} panel The panel
35402 "panelremoved" : true,
35404 * @event beforecollapse
35405 * Fires when this region before collapse.
35406 * @param {Roo.LayoutRegion} this
35408 "beforecollapse" : true,
35411 * Fires when this region is collapsed.
35412 * @param {Roo.LayoutRegion} this
35414 "collapsed" : true,
35417 * Fires when this region is expanded.
35418 * @param {Roo.LayoutRegion} this
35423 * Fires when this region is slid into view.
35424 * @param {Roo.LayoutRegion} this
35426 "slideshow" : true,
35429 * Fires when this region slides out of view.
35430 * @param {Roo.LayoutRegion} this
35432 "slidehide" : true,
35434 * @event panelactivated
35435 * Fires when a panel is activated.
35436 * @param {Roo.LayoutRegion} this
35437 * @param {Roo.ContentPanel} panel The activated panel
35439 "panelactivated" : true,
35442 * Fires when the user resizes this region.
35443 * @param {Roo.LayoutRegion} this
35444 * @param {Number} newSize The new size (width for east/west, height for north/south)
35448 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35449 this.panels = new Roo.util.MixedCollection();
35450 this.panels.getKey = this.getPanelId.createDelegate(this);
35452 this.activePanel = null;
35453 // ensure listeners are added...
35455 if (config.listeners || config.events) {
35456 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35457 listeners : config.listeners || {},
35458 events : config.events || {}
35462 if(skipConfig !== true){
35463 this.applyConfig(config);
35467 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35469 getPanelId : function(p){
35473 applyConfig : function(config){
35474 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35475 this.config = config;
35480 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35481 * the width, for horizontal (north, south) the height.
35482 * @param {Number} newSize The new width or height
35484 resizeTo : function(newSize){
35485 var el = this.el ? this.el :
35486 (this.activePanel ? this.activePanel.getEl() : null);
35488 switch(this.position){
35491 el.setWidth(newSize);
35492 this.fireEvent("resized", this, newSize);
35496 el.setHeight(newSize);
35497 this.fireEvent("resized", this, newSize);
35503 getBox : function(){
35504 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35507 getMargins : function(){
35508 return this.margins;
35511 updateBox : function(box){
35513 var el = this.activePanel.getEl();
35514 el.dom.style.left = box.x + "px";
35515 el.dom.style.top = box.y + "px";
35516 this.activePanel.setSize(box.width, box.height);
35520 * Returns the container element for this region.
35521 * @return {Roo.Element}
35523 getEl : function(){
35524 return this.activePanel;
35528 * Returns true if this region is currently visible.
35529 * @return {Boolean}
35531 isVisible : function(){
35532 return this.activePanel ? true : false;
35535 setActivePanel : function(panel){
35536 panel = this.getPanel(panel);
35537 if(this.activePanel && this.activePanel != panel){
35538 this.activePanel.setActiveState(false);
35539 this.activePanel.getEl().setLeftTop(-10000,-10000);
35541 this.activePanel = panel;
35542 panel.setActiveState(true);
35544 panel.setSize(this.box.width, this.box.height);
35546 this.fireEvent("panelactivated", this, panel);
35547 this.fireEvent("invalidated");
35551 * Show the specified panel.
35552 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35553 * @return {Roo.ContentPanel} The shown panel or null
35555 showPanel : function(panel){
35556 panel = this.getPanel(panel);
35558 this.setActivePanel(panel);
35564 * Get the active panel for this region.
35565 * @return {Roo.ContentPanel} The active panel or null
35567 getActivePanel : function(){
35568 return this.activePanel;
35572 * Add the passed ContentPanel(s)
35573 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35574 * @return {Roo.ContentPanel} The panel added (if only one was added)
35576 add : function(panel){
35577 if(arguments.length > 1){
35578 for(var i = 0, len = arguments.length; i < len; i++) {
35579 this.add(arguments[i]);
35583 if(this.hasPanel(panel)){
35584 this.showPanel(panel);
35587 var el = panel.getEl();
35588 if(el.dom.parentNode != this.mgr.el.dom){
35589 this.mgr.el.dom.appendChild(el.dom);
35591 if(panel.setRegion){
35592 panel.setRegion(this);
35594 this.panels.add(panel);
35595 el.setStyle("position", "absolute");
35596 if(!panel.background){
35597 this.setActivePanel(panel);
35598 if(this.config.initialSize && this.panels.getCount()==1){
35599 this.resizeTo(this.config.initialSize);
35602 this.fireEvent("paneladded", this, panel);
35607 * Returns true if the panel is in this region.
35608 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35609 * @return {Boolean}
35611 hasPanel : function(panel){
35612 if(typeof panel == "object"){ // must be panel obj
35613 panel = panel.getId();
35615 return this.getPanel(panel) ? true : false;
35619 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35620 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35621 * @param {Boolean} preservePanel Overrides the config preservePanel option
35622 * @return {Roo.ContentPanel} The panel that was removed
35624 remove : function(panel, preservePanel){
35625 panel = this.getPanel(panel);
35630 this.fireEvent("beforeremove", this, panel, e);
35631 if(e.cancel === true){
35634 var panelId = panel.getId();
35635 this.panels.removeKey(panelId);
35640 * Returns the panel specified or null if it's not in this region.
35641 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35642 * @return {Roo.ContentPanel}
35644 getPanel : function(id){
35645 if(typeof id == "object"){ // must be panel obj
35648 return this.panels.get(id);
35652 * Returns this regions position (north/south/east/west/center).
35655 getPosition: function(){
35656 return this.position;
35660 * Ext JS Library 1.1.1
35661 * Copyright(c) 2006-2007, Ext JS, LLC.
35663 * Originally Released Under LGPL - original licence link has changed is not relivant.
35666 * <script type="text/javascript">
35670 * @class Roo.bootstrap.layout.Region
35671 * @extends Roo.bootstrap.layout.Basic
35672 * This class represents a region in a layout manager.
35674 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35675 * @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})
35676 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35677 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35678 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35679 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35680 * @cfg {String} title The title for the region (overrides panel titles)
35681 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35682 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35683 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35684 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35685 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35686 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35687 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35688 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35689 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35690 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35692 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35693 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35694 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35695 * @cfg {Number} width For East/West panels
35696 * @cfg {Number} height For North/South panels
35697 * @cfg {Boolean} split To show the splitter
35698 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35700 * @cfg {string} cls Extra CSS classes to add to region
35702 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35703 * @cfg {string} region the region that it inhabits..
35706 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35707 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35709 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35710 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35711 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35713 Roo.bootstrap.layout.Region = function(config)
35715 this.applyConfig(config);
35717 var mgr = config.mgr;
35718 var pos = config.region;
35719 config.skipConfig = true;
35720 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35723 this.onRender(mgr.el);
35726 this.visible = true;
35727 this.collapsed = false;
35728 this.unrendered_panels = [];
35731 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35733 position: '', // set by wrapper (eg. north/south etc..)
35734 unrendered_panels : null, // unrendered panels.
35735 createBody : function(){
35736 /** This region's body element
35737 * @type Roo.Element */
35738 this.bodyEl = this.el.createChild({
35740 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35744 onRender: function(ctr, pos)
35746 var dh = Roo.DomHelper;
35747 /** This region's container element
35748 * @type Roo.Element */
35749 this.el = dh.append(ctr.dom, {
35751 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35753 /** This region's title element
35754 * @type Roo.Element */
35756 this.titleEl = dh.append(this.el.dom,
35759 unselectable: "on",
35760 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35762 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35763 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35766 this.titleEl.enableDisplayMode();
35767 /** This region's title text element
35768 * @type HTMLElement */
35769 this.titleTextEl = this.titleEl.dom.firstChild;
35770 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35772 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35773 this.closeBtn.enableDisplayMode();
35774 this.closeBtn.on("click", this.closeClicked, this);
35775 this.closeBtn.hide();
35777 this.createBody(this.config);
35778 if(this.config.hideWhenEmpty){
35780 this.on("paneladded", this.validateVisibility, this);
35781 this.on("panelremoved", this.validateVisibility, this);
35783 if(this.autoScroll){
35784 this.bodyEl.setStyle("overflow", "auto");
35786 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35788 //if(c.titlebar !== false){
35789 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35790 this.titleEl.hide();
35792 this.titleEl.show();
35793 if(this.config.title){
35794 this.titleTextEl.innerHTML = this.config.title;
35798 if(this.config.collapsed){
35799 this.collapse(true);
35801 if(this.config.hidden){
35805 if (this.unrendered_panels && this.unrendered_panels.length) {
35806 for (var i =0;i< this.unrendered_panels.length; i++) {
35807 this.add(this.unrendered_panels[i]);
35809 this.unrendered_panels = null;
35815 applyConfig : function(c)
35818 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35819 var dh = Roo.DomHelper;
35820 if(c.titlebar !== false){
35821 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35822 this.collapseBtn.on("click", this.collapse, this);
35823 this.collapseBtn.enableDisplayMode();
35825 if(c.showPin === true || this.showPin){
35826 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35827 this.stickBtn.enableDisplayMode();
35828 this.stickBtn.on("click", this.expand, this);
35829 this.stickBtn.hide();
35834 /** This region's collapsed element
35835 * @type Roo.Element */
35838 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35839 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35842 if(c.floatable !== false){
35843 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35844 this.collapsedEl.on("click", this.collapseClick, this);
35847 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35848 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35849 id: "message", unselectable: "on", style:{"float":"left"}});
35850 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35852 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35853 this.expandBtn.on("click", this.expand, this);
35857 if(this.collapseBtn){
35858 this.collapseBtn.setVisible(c.collapsible == true);
35861 this.cmargins = c.cmargins || this.cmargins ||
35862 (this.position == "west" || this.position == "east" ?
35863 {top: 0, left: 2, right:2, bottom: 0} :
35864 {top: 2, left: 0, right:0, bottom: 2});
35866 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35869 this.bottomTabs = c.tabPosition != "top";
35871 this.autoScroll = c.autoScroll || false;
35876 this.duration = c.duration || .30;
35877 this.slideDuration = c.slideDuration || .45;
35882 * Returns true if this region is currently visible.
35883 * @return {Boolean}
35885 isVisible : function(){
35886 return this.visible;
35890 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35891 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35893 //setCollapsedTitle : function(title){
35894 // title = title || " ";
35895 // if(this.collapsedTitleTextEl){
35896 // this.collapsedTitleTextEl.innerHTML = title;
35900 getBox : function(){
35902 // if(!this.collapsed){
35903 b = this.el.getBox(false, true);
35905 // b = this.collapsedEl.getBox(false, true);
35910 getMargins : function(){
35911 return this.margins;
35912 //return this.collapsed ? this.cmargins : this.margins;
35915 highlight : function(){
35916 this.el.addClass("x-layout-panel-dragover");
35919 unhighlight : function(){
35920 this.el.removeClass("x-layout-panel-dragover");
35923 updateBox : function(box)
35925 if (!this.bodyEl) {
35926 return; // not rendered yet..
35930 if(!this.collapsed){
35931 this.el.dom.style.left = box.x + "px";
35932 this.el.dom.style.top = box.y + "px";
35933 this.updateBody(box.width, box.height);
35935 this.collapsedEl.dom.style.left = box.x + "px";
35936 this.collapsedEl.dom.style.top = box.y + "px";
35937 this.collapsedEl.setSize(box.width, box.height);
35940 this.tabs.autoSizeTabs();
35944 updateBody : function(w, h)
35947 this.el.setWidth(w);
35948 w -= this.el.getBorderWidth("rl");
35949 if(this.config.adjustments){
35950 w += this.config.adjustments[0];
35953 if(h !== null && h > 0){
35954 this.el.setHeight(h);
35955 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35956 h -= this.el.getBorderWidth("tb");
35957 if(this.config.adjustments){
35958 h += this.config.adjustments[1];
35960 this.bodyEl.setHeight(h);
35962 h = this.tabs.syncHeight(h);
35965 if(this.panelSize){
35966 w = w !== null ? w : this.panelSize.width;
35967 h = h !== null ? h : this.panelSize.height;
35969 if(this.activePanel){
35970 var el = this.activePanel.getEl();
35971 w = w !== null ? w : el.getWidth();
35972 h = h !== null ? h : el.getHeight();
35973 this.panelSize = {width: w, height: h};
35974 this.activePanel.setSize(w, h);
35976 if(Roo.isIE && this.tabs){
35977 this.tabs.el.repaint();
35982 * Returns the container element for this region.
35983 * @return {Roo.Element}
35985 getEl : function(){
35990 * Hides this region.
35993 //if(!this.collapsed){
35994 this.el.dom.style.left = "-2000px";
35997 // this.collapsedEl.dom.style.left = "-2000px";
35998 // this.collapsedEl.hide();
36000 this.visible = false;
36001 this.fireEvent("visibilitychange", this, false);
36005 * Shows this region if it was previously hidden.
36008 //if(!this.collapsed){
36011 // this.collapsedEl.show();
36013 this.visible = true;
36014 this.fireEvent("visibilitychange", this, true);
36017 closeClicked : function(){
36018 if(this.activePanel){
36019 this.remove(this.activePanel);
36023 collapseClick : function(e){
36025 e.stopPropagation();
36028 e.stopPropagation();
36034 * Collapses this region.
36035 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36038 collapse : function(skipAnim, skipCheck = false){
36039 if(this.collapsed) {
36043 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36045 this.collapsed = true;
36047 this.split.el.hide();
36049 if(this.config.animate && skipAnim !== true){
36050 this.fireEvent("invalidated", this);
36051 this.animateCollapse();
36053 this.el.setLocation(-20000,-20000);
36055 this.collapsedEl.show();
36056 this.fireEvent("collapsed", this);
36057 this.fireEvent("invalidated", this);
36063 animateCollapse : function(){
36068 * Expands this region if it was previously collapsed.
36069 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36070 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36073 expand : function(e, skipAnim){
36075 e.stopPropagation();
36077 if(!this.collapsed || this.el.hasActiveFx()) {
36081 this.afterSlideIn();
36084 this.collapsed = false;
36085 if(this.config.animate && skipAnim !== true){
36086 this.animateExpand();
36090 this.split.el.show();
36092 this.collapsedEl.setLocation(-2000,-2000);
36093 this.collapsedEl.hide();
36094 this.fireEvent("invalidated", this);
36095 this.fireEvent("expanded", this);
36099 animateExpand : function(){
36103 initTabs : function()
36105 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36107 var ts = new Roo.bootstrap.panel.Tabs({
36108 el: this.bodyEl.dom,
36109 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36110 disableTooltips: this.config.disableTabTips,
36111 toolbar : this.config.toolbar
36114 if(this.config.hideTabs){
36115 ts.stripWrap.setDisplayed(false);
36118 ts.resizeTabs = this.config.resizeTabs === true;
36119 ts.minTabWidth = this.config.minTabWidth || 40;
36120 ts.maxTabWidth = this.config.maxTabWidth || 250;
36121 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36122 ts.monitorResize = false;
36123 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36124 ts.bodyEl.addClass('roo-layout-tabs-body');
36125 this.panels.each(this.initPanelAsTab, this);
36128 initPanelAsTab : function(panel){
36129 var ti = this.tabs.addTab(
36133 this.config.closeOnTab && panel.isClosable(),
36136 if(panel.tabTip !== undefined){
36137 ti.setTooltip(panel.tabTip);
36139 ti.on("activate", function(){
36140 this.setActivePanel(panel);
36143 if(this.config.closeOnTab){
36144 ti.on("beforeclose", function(t, e){
36146 this.remove(panel);
36150 panel.tabItem = ti;
36155 updatePanelTitle : function(panel, title)
36157 if(this.activePanel == panel){
36158 this.updateTitle(title);
36161 var ti = this.tabs.getTab(panel.getEl().id);
36163 if(panel.tabTip !== undefined){
36164 ti.setTooltip(panel.tabTip);
36169 updateTitle : function(title){
36170 if(this.titleTextEl && !this.config.title){
36171 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36175 setActivePanel : function(panel)
36177 panel = this.getPanel(panel);
36178 if(this.activePanel && this.activePanel != panel){
36179 if(this.activePanel.setActiveState(false) === false){
36183 this.activePanel = panel;
36184 panel.setActiveState(true);
36185 if(this.panelSize){
36186 panel.setSize(this.panelSize.width, this.panelSize.height);
36189 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36191 this.updateTitle(panel.getTitle());
36193 this.fireEvent("invalidated", this);
36195 this.fireEvent("panelactivated", this, panel);
36199 * Shows the specified panel.
36200 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36201 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36203 showPanel : function(panel)
36205 panel = this.getPanel(panel);
36208 var tab = this.tabs.getTab(panel.getEl().id);
36209 if(tab.isHidden()){
36210 this.tabs.unhideTab(tab.id);
36214 this.setActivePanel(panel);
36221 * Get the active panel for this region.
36222 * @return {Roo.ContentPanel} The active panel or null
36224 getActivePanel : function(){
36225 return this.activePanel;
36228 validateVisibility : function(){
36229 if(this.panels.getCount() < 1){
36230 this.updateTitle(" ");
36231 this.closeBtn.hide();
36234 if(!this.isVisible()){
36241 * Adds the passed ContentPanel(s) to this region.
36242 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36243 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36245 add : function(panel)
36247 if(arguments.length > 1){
36248 for(var i = 0, len = arguments.length; i < len; i++) {
36249 this.add(arguments[i]);
36254 // if we have not been rendered yet, then we can not really do much of this..
36255 if (!this.bodyEl) {
36256 this.unrendered_panels.push(panel);
36263 if(this.hasPanel(panel)){
36264 this.showPanel(panel);
36267 panel.setRegion(this);
36268 this.panels.add(panel);
36269 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36270 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36271 // and hide them... ???
36272 this.bodyEl.dom.appendChild(panel.getEl().dom);
36273 if(panel.background !== true){
36274 this.setActivePanel(panel);
36276 this.fireEvent("paneladded", this, panel);
36283 this.initPanelAsTab(panel);
36287 if(panel.background !== true){
36288 this.tabs.activate(panel.getEl().id);
36290 this.fireEvent("paneladded", this, panel);
36295 * Hides the tab for the specified panel.
36296 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36298 hidePanel : function(panel){
36299 if(this.tabs && (panel = this.getPanel(panel))){
36300 this.tabs.hideTab(panel.getEl().id);
36305 * Unhides the tab for a previously hidden panel.
36306 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36308 unhidePanel : function(panel){
36309 if(this.tabs && (panel = this.getPanel(panel))){
36310 this.tabs.unhideTab(panel.getEl().id);
36314 clearPanels : function(){
36315 while(this.panels.getCount() > 0){
36316 this.remove(this.panels.first());
36321 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36322 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36323 * @param {Boolean} preservePanel Overrides the config preservePanel option
36324 * @return {Roo.ContentPanel} The panel that was removed
36326 remove : function(panel, preservePanel)
36328 panel = this.getPanel(panel);
36333 this.fireEvent("beforeremove", this, panel, e);
36334 if(e.cancel === true){
36337 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36338 var panelId = panel.getId();
36339 this.panels.removeKey(panelId);
36341 document.body.appendChild(panel.getEl().dom);
36344 this.tabs.removeTab(panel.getEl().id);
36345 }else if (!preservePanel){
36346 this.bodyEl.dom.removeChild(panel.getEl().dom);
36348 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36349 var p = this.panels.first();
36350 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36351 tempEl.appendChild(p.getEl().dom);
36352 this.bodyEl.update("");
36353 this.bodyEl.dom.appendChild(p.getEl().dom);
36355 this.updateTitle(p.getTitle());
36357 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36358 this.setActivePanel(p);
36360 panel.setRegion(null);
36361 if(this.activePanel == panel){
36362 this.activePanel = null;
36364 if(this.config.autoDestroy !== false && preservePanel !== true){
36365 try{panel.destroy();}catch(e){}
36367 this.fireEvent("panelremoved", this, panel);
36372 * Returns the TabPanel component used by this region
36373 * @return {Roo.TabPanel}
36375 getTabs : function(){
36379 createTool : function(parentEl, className){
36380 var btn = Roo.DomHelper.append(parentEl, {
36382 cls: "x-layout-tools-button",
36385 cls: "roo-layout-tools-button-inner " + className,
36389 btn.addClassOnOver("roo-layout-tools-button-over");
36394 * Ext JS Library 1.1.1
36395 * Copyright(c) 2006-2007, Ext JS, LLC.
36397 * Originally Released Under LGPL - original licence link has changed is not relivant.
36400 * <script type="text/javascript">
36406 * @class Roo.SplitLayoutRegion
36407 * @extends Roo.LayoutRegion
36408 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36410 Roo.bootstrap.layout.Split = function(config){
36411 this.cursor = config.cursor;
36412 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36415 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36417 splitTip : "Drag to resize.",
36418 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36419 useSplitTips : false,
36421 applyConfig : function(config){
36422 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36425 onRender : function(ctr,pos) {
36427 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36428 if(!this.config.split){
36433 var splitEl = Roo.DomHelper.append(ctr.dom, {
36435 id: this.el.id + "-split",
36436 cls: "roo-layout-split roo-layout-split-"+this.position,
36439 /** The SplitBar for this region
36440 * @type Roo.SplitBar */
36441 // does not exist yet...
36442 Roo.log([this.position, this.orientation]);
36444 this.split = new Roo.bootstrap.SplitBar({
36445 dragElement : splitEl,
36446 resizingElement: this.el,
36447 orientation : this.orientation
36450 this.split.on("moved", this.onSplitMove, this);
36451 this.split.useShim = this.config.useShim === true;
36452 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36453 if(this.useSplitTips){
36454 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36456 //if(config.collapsible){
36457 // this.split.el.on("dblclick", this.collapse, this);
36460 if(typeof this.config.minSize != "undefined"){
36461 this.split.minSize = this.config.minSize;
36463 if(typeof this.config.maxSize != "undefined"){
36464 this.split.maxSize = this.config.maxSize;
36466 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36467 this.hideSplitter();
36472 getHMaxSize : function(){
36473 var cmax = this.config.maxSize || 10000;
36474 var center = this.mgr.getRegion("center");
36475 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36478 getVMaxSize : function(){
36479 var cmax = this.config.maxSize || 10000;
36480 var center = this.mgr.getRegion("center");
36481 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36484 onSplitMove : function(split, newSize){
36485 this.fireEvent("resized", this, newSize);
36489 * Returns the {@link Roo.SplitBar} for this region.
36490 * @return {Roo.SplitBar}
36492 getSplitBar : function(){
36497 this.hideSplitter();
36498 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36501 hideSplitter : function(){
36503 this.split.el.setLocation(-2000,-2000);
36504 this.split.el.hide();
36510 this.split.el.show();
36512 Roo.bootstrap.layout.Split.superclass.show.call(this);
36515 beforeSlide: function(){
36516 if(Roo.isGecko){// firefox overflow auto bug workaround
36517 this.bodyEl.clip();
36519 this.tabs.bodyEl.clip();
36521 if(this.activePanel){
36522 this.activePanel.getEl().clip();
36524 if(this.activePanel.beforeSlide){
36525 this.activePanel.beforeSlide();
36531 afterSlide : function(){
36532 if(Roo.isGecko){// firefox overflow auto bug workaround
36533 this.bodyEl.unclip();
36535 this.tabs.bodyEl.unclip();
36537 if(this.activePanel){
36538 this.activePanel.getEl().unclip();
36539 if(this.activePanel.afterSlide){
36540 this.activePanel.afterSlide();
36546 initAutoHide : function(){
36547 if(this.autoHide !== false){
36548 if(!this.autoHideHd){
36549 var st = new Roo.util.DelayedTask(this.slideIn, this);
36550 this.autoHideHd = {
36551 "mouseout": function(e){
36552 if(!e.within(this.el, true)){
36556 "mouseover" : function(e){
36562 this.el.on(this.autoHideHd);
36566 clearAutoHide : function(){
36567 if(this.autoHide !== false){
36568 this.el.un("mouseout", this.autoHideHd.mouseout);
36569 this.el.un("mouseover", this.autoHideHd.mouseover);
36573 clearMonitor : function(){
36574 Roo.get(document).un("click", this.slideInIf, this);
36577 // these names are backwards but not changed for compat
36578 slideOut : function(){
36579 if(this.isSlid || this.el.hasActiveFx()){
36582 this.isSlid = true;
36583 if(this.collapseBtn){
36584 this.collapseBtn.hide();
36586 this.closeBtnState = this.closeBtn.getStyle('display');
36587 this.closeBtn.hide();
36589 this.stickBtn.show();
36592 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36593 this.beforeSlide();
36594 this.el.setStyle("z-index", 10001);
36595 this.el.slideIn(this.getSlideAnchor(), {
36596 callback: function(){
36598 this.initAutoHide();
36599 Roo.get(document).on("click", this.slideInIf, this);
36600 this.fireEvent("slideshow", this);
36607 afterSlideIn : function(){
36608 this.clearAutoHide();
36609 this.isSlid = false;
36610 this.clearMonitor();
36611 this.el.setStyle("z-index", "");
36612 if(this.collapseBtn){
36613 this.collapseBtn.show();
36615 this.closeBtn.setStyle('display', this.closeBtnState);
36617 this.stickBtn.hide();
36619 this.fireEvent("slidehide", this);
36622 slideIn : function(cb){
36623 if(!this.isSlid || this.el.hasActiveFx()){
36627 this.isSlid = false;
36628 this.beforeSlide();
36629 this.el.slideOut(this.getSlideAnchor(), {
36630 callback: function(){
36631 this.el.setLeftTop(-10000, -10000);
36633 this.afterSlideIn();
36641 slideInIf : function(e){
36642 if(!e.within(this.el)){
36647 animateCollapse : function(){
36648 this.beforeSlide();
36649 this.el.setStyle("z-index", 20000);
36650 var anchor = this.getSlideAnchor();
36651 this.el.slideOut(anchor, {
36652 callback : function(){
36653 this.el.setStyle("z-index", "");
36654 this.collapsedEl.slideIn(anchor, {duration:.3});
36656 this.el.setLocation(-10000,-10000);
36658 this.fireEvent("collapsed", this);
36665 animateExpand : function(){
36666 this.beforeSlide();
36667 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36668 this.el.setStyle("z-index", 20000);
36669 this.collapsedEl.hide({
36672 this.el.slideIn(this.getSlideAnchor(), {
36673 callback : function(){
36674 this.el.setStyle("z-index", "");
36677 this.split.el.show();
36679 this.fireEvent("invalidated", this);
36680 this.fireEvent("expanded", this);
36708 getAnchor : function(){
36709 return this.anchors[this.position];
36712 getCollapseAnchor : function(){
36713 return this.canchors[this.position];
36716 getSlideAnchor : function(){
36717 return this.sanchors[this.position];
36720 getAlignAdj : function(){
36721 var cm = this.cmargins;
36722 switch(this.position){
36738 getExpandAdj : function(){
36739 var c = this.collapsedEl, cm = this.cmargins;
36740 switch(this.position){
36742 return [-(cm.right+c.getWidth()+cm.left), 0];
36745 return [cm.right+c.getWidth()+cm.left, 0];
36748 return [0, -(cm.top+cm.bottom+c.getHeight())];
36751 return [0, cm.top+cm.bottom+c.getHeight()];
36757 * Ext JS Library 1.1.1
36758 * Copyright(c) 2006-2007, Ext JS, LLC.
36760 * Originally Released Under LGPL - original licence link has changed is not relivant.
36763 * <script type="text/javascript">
36766 * These classes are private internal classes
36768 Roo.bootstrap.layout.Center = function(config){
36769 config.region = "center";
36770 Roo.bootstrap.layout.Region.call(this, config);
36771 this.visible = true;
36772 this.minWidth = config.minWidth || 20;
36773 this.minHeight = config.minHeight || 20;
36776 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36778 // center panel can't be hidden
36782 // center panel can't be hidden
36785 getMinWidth: function(){
36786 return this.minWidth;
36789 getMinHeight: function(){
36790 return this.minHeight;
36803 Roo.bootstrap.layout.North = function(config)
36805 config.region = 'north';
36806 config.cursor = 'n-resize';
36808 Roo.bootstrap.layout.Split.call(this, config);
36812 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36813 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36814 this.split.el.addClass("roo-layout-split-v");
36816 var size = config.initialSize || config.height;
36817 if(typeof size != "undefined"){
36818 this.el.setHeight(size);
36821 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36823 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36827 getBox : function(){
36828 if(this.collapsed){
36829 return this.collapsedEl.getBox();
36831 var box = this.el.getBox();
36833 box.height += this.split.el.getHeight();
36838 updateBox : function(box){
36839 if(this.split && !this.collapsed){
36840 box.height -= this.split.el.getHeight();
36841 this.split.el.setLeft(box.x);
36842 this.split.el.setTop(box.y+box.height);
36843 this.split.el.setWidth(box.width);
36845 if(this.collapsed){
36846 this.updateBody(box.width, null);
36848 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36856 Roo.bootstrap.layout.South = function(config){
36857 config.region = 'south';
36858 config.cursor = 's-resize';
36859 Roo.bootstrap.layout.Split.call(this, config);
36861 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36862 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36863 this.split.el.addClass("roo-layout-split-v");
36865 var size = config.initialSize || config.height;
36866 if(typeof size != "undefined"){
36867 this.el.setHeight(size);
36871 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36872 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36873 getBox : function(){
36874 if(this.collapsed){
36875 return this.collapsedEl.getBox();
36877 var box = this.el.getBox();
36879 var sh = this.split.el.getHeight();
36886 updateBox : function(box){
36887 if(this.split && !this.collapsed){
36888 var sh = this.split.el.getHeight();
36891 this.split.el.setLeft(box.x);
36892 this.split.el.setTop(box.y-sh);
36893 this.split.el.setWidth(box.width);
36895 if(this.collapsed){
36896 this.updateBody(box.width, null);
36898 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36902 Roo.bootstrap.layout.East = function(config){
36903 config.region = "east";
36904 config.cursor = "e-resize";
36905 Roo.bootstrap.layout.Split.call(this, config);
36907 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36908 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36909 this.split.el.addClass("roo-layout-split-h");
36911 var size = config.initialSize || config.width;
36912 if(typeof size != "undefined"){
36913 this.el.setWidth(size);
36916 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36917 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36918 getBox : function(){
36919 if(this.collapsed){
36920 return this.collapsedEl.getBox();
36922 var box = this.el.getBox();
36924 var sw = this.split.el.getWidth();
36931 updateBox : function(box){
36932 if(this.split && !this.collapsed){
36933 var sw = this.split.el.getWidth();
36935 this.split.el.setLeft(box.x);
36936 this.split.el.setTop(box.y);
36937 this.split.el.setHeight(box.height);
36940 if(this.collapsed){
36941 this.updateBody(null, box.height);
36943 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36947 Roo.bootstrap.layout.West = function(config){
36948 config.region = "west";
36949 config.cursor = "w-resize";
36951 Roo.bootstrap.layout.Split.call(this, config);
36953 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36954 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36955 this.split.el.addClass("roo-layout-split-h");
36959 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36960 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36962 onRender: function(ctr, pos)
36964 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36965 var size = this.config.initialSize || this.config.width;
36966 if(typeof size != "undefined"){
36967 this.el.setWidth(size);
36971 getBox : function(){
36972 if(this.collapsed){
36973 return this.collapsedEl.getBox();
36975 var box = this.el.getBox();
36977 box.width += this.split.el.getWidth();
36982 updateBox : function(box){
36983 if(this.split && !this.collapsed){
36984 var sw = this.split.el.getWidth();
36986 this.split.el.setLeft(box.x+box.width);
36987 this.split.el.setTop(box.y);
36988 this.split.el.setHeight(box.height);
36990 if(this.collapsed){
36991 this.updateBody(null, box.height);
36993 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36996 Roo.namespace("Roo.bootstrap.panel");/*
36998 * Ext JS Library 1.1.1
36999 * Copyright(c) 2006-2007, Ext JS, LLC.
37001 * Originally Released Under LGPL - original licence link has changed is not relivant.
37004 * <script type="text/javascript">
37007 * @class Roo.ContentPanel
37008 * @extends Roo.util.Observable
37009 * A basic ContentPanel element.
37010 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37011 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37012 * @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
37013 * @cfg {Boolean} closable True if the panel can be closed/removed
37014 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37015 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37016 * @cfg {Toolbar} toolbar A toolbar for this panel
37017 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37018 * @cfg {String} title The title for this panel
37019 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37020 * @cfg {String} url Calls {@link #setUrl} with this value
37021 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37022 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37023 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37024 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37025 * @cfg {Boolean} badges render the badges
37028 * Create a new ContentPanel.
37029 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37030 * @param {String/Object} config A string to set only the title or a config object
37031 * @param {String} content (optional) Set the HTML content for this panel
37032 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37034 Roo.bootstrap.panel.Content = function( config){
37036 this.tpl = config.tpl || false;
37038 var el = config.el;
37039 var content = config.content;
37041 if(config.autoCreate){ // xtype is available if this is called from factory
37044 this.el = Roo.get(el);
37045 if(!this.el && config && config.autoCreate){
37046 if(typeof config.autoCreate == "object"){
37047 if(!config.autoCreate.id){
37048 config.autoCreate.id = config.id||el;
37050 this.el = Roo.DomHelper.append(document.body,
37051 config.autoCreate, true);
37053 var elcfg = { tag: "div",
37054 cls: "roo-layout-inactive-content",
37058 elcfg.html = config.html;
37062 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37065 this.closable = false;
37066 this.loaded = false;
37067 this.active = false;
37070 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37072 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37074 this.wrapEl = this.el; //this.el.wrap();
37076 if (config.toolbar.items) {
37077 ti = config.toolbar.items ;
37078 delete config.toolbar.items ;
37082 this.toolbar.render(this.wrapEl, 'before');
37083 for(var i =0;i < ti.length;i++) {
37084 // Roo.log(['add child', items[i]]);
37085 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37087 this.toolbar.items = nitems;
37088 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37089 delete config.toolbar;
37093 // xtype created footer. - not sure if will work as we normally have to render first..
37094 if (this.footer && !this.footer.el && this.footer.xtype) {
37095 if (!this.wrapEl) {
37096 this.wrapEl = this.el.wrap();
37099 this.footer.container = this.wrapEl.createChild();
37101 this.footer = Roo.factory(this.footer, Roo);
37106 if(typeof config == "string"){
37107 this.title = config;
37109 Roo.apply(this, config);
37113 this.resizeEl = Roo.get(this.resizeEl, true);
37115 this.resizeEl = this.el;
37117 // handle view.xtype
37125 * Fires when this panel is activated.
37126 * @param {Roo.ContentPanel} this
37130 * @event deactivate
37131 * Fires when this panel is activated.
37132 * @param {Roo.ContentPanel} this
37134 "deactivate" : true,
37138 * Fires when this panel is resized if fitToFrame is true.
37139 * @param {Roo.ContentPanel} this
37140 * @param {Number} width The width after any component adjustments
37141 * @param {Number} height The height after any component adjustments
37147 * Fires when this tab is created
37148 * @param {Roo.ContentPanel} this
37159 if(this.autoScroll){
37160 this.resizeEl.setStyle("overflow", "auto");
37162 // fix randome scrolling
37163 //this.el.on('scroll', function() {
37164 // Roo.log('fix random scolling');
37165 // this.scrollTo('top',0);
37168 content = content || this.content;
37170 this.setContent(content);
37172 if(config && config.url){
37173 this.setUrl(this.url, this.params, this.loadOnce);
37178 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37180 if (this.view && typeof(this.view.xtype) != 'undefined') {
37181 this.view.el = this.el.appendChild(document.createElement("div"));
37182 this.view = Roo.factory(this.view);
37183 this.view.render && this.view.render(false, '');
37187 this.fireEvent('render', this);
37190 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37194 setRegion : function(region){
37195 this.region = region;
37196 this.setActiveClass(region && !this.background);
37200 setActiveClass: function(state)
37203 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37204 this.el.setStyle('position','relative');
37206 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37207 this.el.setStyle('position', 'absolute');
37212 * Returns the toolbar for this Panel if one was configured.
37213 * @return {Roo.Toolbar}
37215 getToolbar : function(){
37216 return this.toolbar;
37219 setActiveState : function(active)
37221 this.active = active;
37222 this.setActiveClass(active);
37224 if(this.fireEvent("deactivate", this) === false){
37229 this.fireEvent("activate", this);
37233 * Updates this panel's element
37234 * @param {String} content The new content
37235 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37237 setContent : function(content, loadScripts){
37238 this.el.update(content, loadScripts);
37241 ignoreResize : function(w, h){
37242 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37245 this.lastSize = {width: w, height: h};
37250 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37251 * @return {Roo.UpdateManager} The UpdateManager
37253 getUpdateManager : function(){
37254 return this.el.getUpdateManager();
37257 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37258 * @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:
37261 url: "your-url.php",
37262 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37263 callback: yourFunction,
37264 scope: yourObject, //(optional scope)
37267 text: "Loading...",
37272 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37273 * 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.
37274 * @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}
37275 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37276 * @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.
37277 * @return {Roo.ContentPanel} this
37280 var um = this.el.getUpdateManager();
37281 um.update.apply(um, arguments);
37287 * 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.
37288 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37289 * @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)
37290 * @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)
37291 * @return {Roo.UpdateManager} The UpdateManager
37293 setUrl : function(url, params, loadOnce){
37294 if(this.refreshDelegate){
37295 this.removeListener("activate", this.refreshDelegate);
37297 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37298 this.on("activate", this.refreshDelegate);
37299 return this.el.getUpdateManager();
37302 _handleRefresh : function(url, params, loadOnce){
37303 if(!loadOnce || !this.loaded){
37304 var updater = this.el.getUpdateManager();
37305 updater.update(url, params, this._setLoaded.createDelegate(this));
37309 _setLoaded : function(){
37310 this.loaded = true;
37314 * Returns this panel's id
37317 getId : function(){
37322 * Returns this panel's element - used by regiosn to add.
37323 * @return {Roo.Element}
37325 getEl : function(){
37326 return this.wrapEl || this.el;
37331 adjustForComponents : function(width, height)
37333 //Roo.log('adjustForComponents ');
37334 if(this.resizeEl != this.el){
37335 width -= this.el.getFrameWidth('lr');
37336 height -= this.el.getFrameWidth('tb');
37339 var te = this.toolbar.getEl();
37340 te.setWidth(width);
37341 height -= te.getHeight();
37344 var te = this.footer.getEl();
37345 te.setWidth(width);
37346 height -= te.getHeight();
37350 if(this.adjustments){
37351 width += this.adjustments[0];
37352 height += this.adjustments[1];
37354 return {"width": width, "height": height};
37357 setSize : function(width, height){
37358 if(this.fitToFrame && !this.ignoreResize(width, height)){
37359 if(this.fitContainer && this.resizeEl != this.el){
37360 this.el.setSize(width, height);
37362 var size = this.adjustForComponents(width, height);
37363 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37364 this.fireEvent('resize', this, size.width, size.height);
37369 * Returns this panel's title
37372 getTitle : function(){
37374 if (typeof(this.title) != 'object') {
37379 for (var k in this.title) {
37380 if (!this.title.hasOwnProperty(k)) {
37384 if (k.indexOf('-') >= 0) {
37385 var s = k.split('-');
37386 for (var i = 0; i<s.length; i++) {
37387 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37390 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37397 * Set this panel's title
37398 * @param {String} title
37400 setTitle : function(title){
37401 this.title = title;
37403 this.region.updatePanelTitle(this, title);
37408 * Returns true is this panel was configured to be closable
37409 * @return {Boolean}
37411 isClosable : function(){
37412 return this.closable;
37415 beforeSlide : function(){
37417 this.resizeEl.clip();
37420 afterSlide : function(){
37422 this.resizeEl.unclip();
37426 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37427 * Will fail silently if the {@link #setUrl} method has not been called.
37428 * This does not activate the panel, just updates its content.
37430 refresh : function(){
37431 if(this.refreshDelegate){
37432 this.loaded = false;
37433 this.refreshDelegate();
37438 * Destroys this panel
37440 destroy : function(){
37441 this.el.removeAllListeners();
37442 var tempEl = document.createElement("span");
37443 tempEl.appendChild(this.el.dom);
37444 tempEl.innerHTML = "";
37450 * form - if the content panel contains a form - this is a reference to it.
37451 * @type {Roo.form.Form}
37455 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37456 * This contains a reference to it.
37462 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37472 * @param {Object} cfg Xtype definition of item to add.
37476 getChildContainer: function () {
37477 return this.getEl();
37482 var ret = new Roo.factory(cfg);
37487 if (cfg.xtype.match(/^Form$/)) {
37490 //if (this.footer) {
37491 // el = this.footer.container.insertSibling(false, 'before');
37493 el = this.el.createChild();
37496 this.form = new Roo.form.Form(cfg);
37499 if ( this.form.allItems.length) {
37500 this.form.render(el.dom);
37504 // should only have one of theses..
37505 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37506 // views.. should not be just added - used named prop 'view''
37508 cfg.el = this.el.appendChild(document.createElement("div"));
37511 var ret = new Roo.factory(cfg);
37513 ret.render && ret.render(false, ''); // render blank..
37523 * @class Roo.bootstrap.panel.Grid
37524 * @extends Roo.bootstrap.panel.Content
37526 * Create a new GridPanel.
37527 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37528 * @param {Object} config A the config object
37534 Roo.bootstrap.panel.Grid = function(config)
37538 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37539 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37541 config.el = this.wrapper;
37542 //this.el = this.wrapper;
37544 if (config.container) {
37545 // ctor'ed from a Border/panel.grid
37548 this.wrapper.setStyle("overflow", "hidden");
37549 this.wrapper.addClass('roo-grid-container');
37554 if(config.toolbar){
37555 var tool_el = this.wrapper.createChild();
37556 this.toolbar = Roo.factory(config.toolbar);
37558 if (config.toolbar.items) {
37559 ti = config.toolbar.items ;
37560 delete config.toolbar.items ;
37564 this.toolbar.render(tool_el);
37565 for(var i =0;i < ti.length;i++) {
37566 // Roo.log(['add child', items[i]]);
37567 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37569 this.toolbar.items = nitems;
37571 delete config.toolbar;
37574 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37575 config.grid.scrollBody = true;;
37576 config.grid.monitorWindowResize = false; // turn off autosizing
37577 config.grid.autoHeight = false;
37578 config.grid.autoWidth = false;
37580 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37582 if (config.background) {
37583 // render grid on panel activation (if panel background)
37584 this.on('activate', function(gp) {
37585 if (!gp.grid.rendered) {
37586 gp.grid.render(this.wrapper);
37587 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37592 this.grid.render(this.wrapper);
37593 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37596 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37597 // ??? needed ??? config.el = this.wrapper;
37602 // xtype created footer. - not sure if will work as we normally have to render first..
37603 if (this.footer && !this.footer.el && this.footer.xtype) {
37605 var ctr = this.grid.getView().getFooterPanel(true);
37606 this.footer.dataSource = this.grid.dataSource;
37607 this.footer = Roo.factory(this.footer, Roo);
37608 this.footer.render(ctr);
37618 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37619 getId : function(){
37620 return this.grid.id;
37624 * Returns the grid for this panel
37625 * @return {Roo.bootstrap.Table}
37627 getGrid : function(){
37631 setSize : function(width, height){
37632 if(!this.ignoreResize(width, height)){
37633 var grid = this.grid;
37634 var size = this.adjustForComponents(width, height);
37635 var gridel = grid.getGridEl();
37636 gridel.setSize(size.width, size.height);
37638 var thd = grid.getGridEl().select('thead',true).first();
37639 var tbd = grid.getGridEl().select('tbody', true).first();
37641 tbd.setSize(width, height - thd.getHeight());
37650 beforeSlide : function(){
37651 this.grid.getView().scroller.clip();
37654 afterSlide : function(){
37655 this.grid.getView().scroller.unclip();
37658 destroy : function(){
37659 this.grid.destroy();
37661 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37666 * @class Roo.bootstrap.panel.Nest
37667 * @extends Roo.bootstrap.panel.Content
37669 * Create a new Panel, that can contain a layout.Border.
37672 * @param {Roo.BorderLayout} layout The layout for this panel
37673 * @param {String/Object} config A string to set only the title or a config object
37675 Roo.bootstrap.panel.Nest = function(config)
37677 // construct with only one argument..
37678 /* FIXME - implement nicer consturctors
37679 if (layout.layout) {
37681 layout = config.layout;
37682 delete config.layout;
37684 if (layout.xtype && !layout.getEl) {
37685 // then layout needs constructing..
37686 layout = Roo.factory(layout, Roo);
37690 config.el = config.layout.getEl();
37692 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37694 config.layout.monitorWindowResize = false; // turn off autosizing
37695 this.layout = config.layout;
37696 this.layout.getEl().addClass("roo-layout-nested-layout");
37703 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37705 setSize : function(width, height){
37706 if(!this.ignoreResize(width, height)){
37707 var size = this.adjustForComponents(width, height);
37708 var el = this.layout.getEl();
37709 if (size.height < 1) {
37710 el.setWidth(size.width);
37712 el.setSize(size.width, size.height);
37714 var touch = el.dom.offsetWidth;
37715 this.layout.layout();
37716 // ie requires a double layout on the first pass
37717 if(Roo.isIE && !this.initialized){
37718 this.initialized = true;
37719 this.layout.layout();
37724 // activate all subpanels if not currently active..
37726 setActiveState : function(active){
37727 this.active = active;
37728 this.setActiveClass(active);
37731 this.fireEvent("deactivate", this);
37735 this.fireEvent("activate", this);
37736 // not sure if this should happen before or after..
37737 if (!this.layout) {
37738 return; // should not happen..
37741 for (var r in this.layout.regions) {
37742 reg = this.layout.getRegion(r);
37743 if (reg.getActivePanel()) {
37744 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37745 reg.setActivePanel(reg.getActivePanel());
37748 if (!reg.panels.length) {
37751 reg.showPanel(reg.getPanel(0));
37760 * Returns the nested BorderLayout for this panel
37761 * @return {Roo.BorderLayout}
37763 getLayout : function(){
37764 return this.layout;
37768 * Adds a xtype elements to the layout of the nested panel
37772 xtype : 'ContentPanel',
37779 xtype : 'NestedLayoutPanel',
37785 items : [ ... list of content panels or nested layout panels.. ]
37789 * @param {Object} cfg Xtype definition of item to add.
37791 addxtype : function(cfg) {
37792 return this.layout.addxtype(cfg);
37797 * Ext JS Library 1.1.1
37798 * Copyright(c) 2006-2007, Ext JS, LLC.
37800 * Originally Released Under LGPL - original licence link has changed is not relivant.
37803 * <script type="text/javascript">
37806 * @class Roo.TabPanel
37807 * @extends Roo.util.Observable
37808 * A lightweight tab container.
37812 // basic tabs 1, built from existing content
37813 var tabs = new Roo.TabPanel("tabs1");
37814 tabs.addTab("script", "View Script");
37815 tabs.addTab("markup", "View Markup");
37816 tabs.activate("script");
37818 // more advanced tabs, built from javascript
37819 var jtabs = new Roo.TabPanel("jtabs");
37820 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37822 // set up the UpdateManager
37823 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37824 var updater = tab2.getUpdateManager();
37825 updater.setDefaultUrl("ajax1.htm");
37826 tab2.on('activate', updater.refresh, updater, true);
37828 // Use setUrl for Ajax loading
37829 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37830 tab3.setUrl("ajax2.htm", null, true);
37833 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37836 jtabs.activate("jtabs-1");
37839 * Create a new TabPanel.
37840 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37841 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37843 Roo.bootstrap.panel.Tabs = function(config){
37845 * The container element for this TabPanel.
37846 * @type Roo.Element
37848 this.el = Roo.get(config.el);
37851 if(typeof config == "boolean"){
37852 this.tabPosition = config ? "bottom" : "top";
37854 Roo.apply(this, config);
37858 if(this.tabPosition == "bottom"){
37859 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37860 this.el.addClass("roo-tabs-bottom");
37862 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37863 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37864 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37866 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37868 if(this.tabPosition != "bottom"){
37869 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37870 * @type Roo.Element
37872 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37873 this.el.addClass("roo-tabs-top");
37877 this.bodyEl.setStyle("position", "relative");
37879 this.active = null;
37880 this.activateDelegate = this.activate.createDelegate(this);
37885 * Fires when the active tab changes
37886 * @param {Roo.TabPanel} this
37887 * @param {Roo.TabPanelItem} activePanel The new active tab
37891 * @event beforetabchange
37892 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37893 * @param {Roo.TabPanel} this
37894 * @param {Object} e Set cancel to true on this object to cancel the tab change
37895 * @param {Roo.TabPanelItem} tab The tab being changed to
37897 "beforetabchange" : true
37900 Roo.EventManager.onWindowResize(this.onResize, this);
37901 this.cpad = this.el.getPadding("lr");
37902 this.hiddenCount = 0;
37905 // toolbar on the tabbar support...
37906 if (this.toolbar) {
37907 alert("no toolbar support yet");
37908 this.toolbar = false;
37910 var tcfg = this.toolbar;
37911 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37912 this.toolbar = new Roo.Toolbar(tcfg);
37913 if (Roo.isSafari) {
37914 var tbl = tcfg.container.child('table', true);
37915 tbl.setAttribute('width', '100%');
37923 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37926 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37928 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37930 tabPosition : "top",
37932 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37934 currentTabWidth : 0,
37936 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37940 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37944 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37946 preferredTabWidth : 175,
37948 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37950 resizeTabs : false,
37952 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37954 monitorResize : true,
37956 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37961 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37962 * @param {String} id The id of the div to use <b>or create</b>
37963 * @param {String} text The text for the tab
37964 * @param {String} content (optional) Content to put in the TabPanelItem body
37965 * @param {Boolean} closable (optional) True to create a close icon on the tab
37966 * @return {Roo.TabPanelItem} The created TabPanelItem
37968 addTab : function(id, text, content, closable, tpl)
37970 var item = new Roo.bootstrap.panel.TabItem({
37974 closable : closable,
37977 this.addTabItem(item);
37979 item.setContent(content);
37985 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37986 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37987 * @return {Roo.TabPanelItem}
37989 getTab : function(id){
37990 return this.items[id];
37994 * Hides the {@link Roo.TabPanelItem} with the specified id/index
37995 * @param {String/Number} id The id or index of the TabPanelItem to hide.
37997 hideTab : function(id){
37998 var t = this.items[id];
38001 this.hiddenCount++;
38002 this.autoSizeTabs();
38007 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38008 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38010 unhideTab : function(id){
38011 var t = this.items[id];
38013 t.setHidden(false);
38014 this.hiddenCount--;
38015 this.autoSizeTabs();
38020 * Adds an existing {@link Roo.TabPanelItem}.
38021 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38023 addTabItem : function(item){
38024 this.items[item.id] = item;
38025 this.items.push(item);
38026 // if(this.resizeTabs){
38027 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38028 // this.autoSizeTabs();
38030 // item.autoSize();
38035 * Removes a {@link Roo.TabPanelItem}.
38036 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38038 removeTab : function(id){
38039 var items = this.items;
38040 var tab = items[id];
38041 if(!tab) { return; }
38042 var index = items.indexOf(tab);
38043 if(this.active == tab && items.length > 1){
38044 var newTab = this.getNextAvailable(index);
38049 this.stripEl.dom.removeChild(tab.pnode.dom);
38050 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38051 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38053 items.splice(index, 1);
38054 delete this.items[tab.id];
38055 tab.fireEvent("close", tab);
38056 tab.purgeListeners();
38057 this.autoSizeTabs();
38060 getNextAvailable : function(start){
38061 var items = this.items;
38063 // look for a next tab that will slide over to
38064 // replace the one being removed
38065 while(index < items.length){
38066 var item = items[++index];
38067 if(item && !item.isHidden()){
38071 // if one isn't found select the previous tab (on the left)
38074 var item = items[--index];
38075 if(item && !item.isHidden()){
38083 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38084 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38086 disableTab : function(id){
38087 var tab = this.items[id];
38088 if(tab && this.active != tab){
38094 * Enables a {@link Roo.TabPanelItem} that is disabled.
38095 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38097 enableTab : function(id){
38098 var tab = this.items[id];
38103 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38104 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38105 * @return {Roo.TabPanelItem} The TabPanelItem.
38107 activate : function(id){
38108 var tab = this.items[id];
38112 if(tab == this.active || tab.disabled){
38116 this.fireEvent("beforetabchange", this, e, tab);
38117 if(e.cancel !== true && !tab.disabled){
38119 this.active.hide();
38121 this.active = this.items[id];
38122 this.active.show();
38123 this.fireEvent("tabchange", this, this.active);
38129 * Gets the active {@link Roo.TabPanelItem}.
38130 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38132 getActiveTab : function(){
38133 return this.active;
38137 * Updates the tab body element to fit the height of the container element
38138 * for overflow scrolling
38139 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38141 syncHeight : function(targetHeight){
38142 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38143 var bm = this.bodyEl.getMargins();
38144 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38145 this.bodyEl.setHeight(newHeight);
38149 onResize : function(){
38150 if(this.monitorResize){
38151 this.autoSizeTabs();
38156 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38158 beginUpdate : function(){
38159 this.updating = true;
38163 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38165 endUpdate : function(){
38166 this.updating = false;
38167 this.autoSizeTabs();
38171 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38173 autoSizeTabs : function(){
38174 var count = this.items.length;
38175 var vcount = count - this.hiddenCount;
38176 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38179 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38180 var availWidth = Math.floor(w / vcount);
38181 var b = this.stripBody;
38182 if(b.getWidth() > w){
38183 var tabs = this.items;
38184 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38185 if(availWidth < this.minTabWidth){
38186 /*if(!this.sleft){ // incomplete scrolling code
38187 this.createScrollButtons();
38190 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38193 if(this.currentTabWidth < this.preferredTabWidth){
38194 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38200 * Returns the number of tabs in this TabPanel.
38203 getCount : function(){
38204 return this.items.length;
38208 * Resizes all the tabs to the passed width
38209 * @param {Number} The new width
38211 setTabWidth : function(width){
38212 this.currentTabWidth = width;
38213 for(var i = 0, len = this.items.length; i < len; i++) {
38214 if(!this.items[i].isHidden()) {
38215 this.items[i].setWidth(width);
38221 * Destroys this TabPanel
38222 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38224 destroy : function(removeEl){
38225 Roo.EventManager.removeResizeListener(this.onResize, this);
38226 for(var i = 0, len = this.items.length; i < len; i++){
38227 this.items[i].purgeListeners();
38229 if(removeEl === true){
38230 this.el.update("");
38235 createStrip : function(container)
38237 var strip = document.createElement("nav");
38238 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38239 container.appendChild(strip);
38243 createStripList : function(strip)
38245 // div wrapper for retard IE
38246 // returns the "tr" element.
38247 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38248 //'<div class="x-tabs-strip-wrap">'+
38249 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38250 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38251 return strip.firstChild; //.firstChild.firstChild.firstChild;
38253 createBody : function(container)
38255 var body = document.createElement("div");
38256 Roo.id(body, "tab-body");
38257 //Roo.fly(body).addClass("x-tabs-body");
38258 Roo.fly(body).addClass("tab-content");
38259 container.appendChild(body);
38262 createItemBody :function(bodyEl, id){
38263 var body = Roo.getDom(id);
38265 body = document.createElement("div");
38268 //Roo.fly(body).addClass("x-tabs-item-body");
38269 Roo.fly(body).addClass("tab-pane");
38270 bodyEl.insertBefore(body, bodyEl.firstChild);
38274 createStripElements : function(stripEl, text, closable, tpl)
38276 var td = document.createElement("li"); // was td..
38279 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38282 stripEl.appendChild(td);
38284 td.className = "x-tabs-closable";
38285 if(!this.closeTpl){
38286 this.closeTpl = new Roo.Template(
38287 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38288 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38289 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38292 var el = this.closeTpl.overwrite(td, {"text": text});
38293 var close = el.getElementsByTagName("div")[0];
38294 var inner = el.getElementsByTagName("em")[0];
38295 return {"el": el, "close": close, "inner": inner};
38298 // not sure what this is..
38299 // if(!this.tabTpl){
38300 //this.tabTpl = new Roo.Template(
38301 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38302 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38304 // this.tabTpl = new Roo.Template(
38305 // '<a href="#">' +
38306 // '<span unselectable="on"' +
38307 // (this.disableTooltips ? '' : ' title="{text}"') +
38308 // ' >{text}</span></a>'
38314 var template = tpl || this.tabTpl || false;
38318 template = new Roo.Template(
38320 '<span unselectable="on"' +
38321 (this.disableTooltips ? '' : ' title="{text}"') +
38322 ' >{text}</span></a>'
38326 switch (typeof(template)) {
38330 template = new Roo.Template(template);
38336 var el = template.overwrite(td, {"text": text});
38338 var inner = el.getElementsByTagName("span")[0];
38340 return {"el": el, "inner": inner};
38348 * @class Roo.TabPanelItem
38349 * @extends Roo.util.Observable
38350 * Represents an individual item (tab plus body) in a TabPanel.
38351 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38352 * @param {String} id The id of this TabPanelItem
38353 * @param {String} text The text for the tab of this TabPanelItem
38354 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38356 Roo.bootstrap.panel.TabItem = function(config){
38358 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38359 * @type Roo.TabPanel
38361 this.tabPanel = config.panel;
38363 * The id for this TabPanelItem
38366 this.id = config.id;
38368 this.disabled = false;
38370 this.text = config.text;
38372 this.loaded = false;
38373 this.closable = config.closable;
38376 * The body element for this TabPanelItem.
38377 * @type Roo.Element
38379 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38380 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38381 this.bodyEl.setStyle("display", "block");
38382 this.bodyEl.setStyle("zoom", "1");
38383 //this.hideAction();
38385 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38387 this.el = Roo.get(els.el);
38388 this.inner = Roo.get(els.inner, true);
38389 this.textEl = Roo.get(this.el.dom.firstChild, true);
38390 this.pnode = Roo.get(els.el.parentNode, true);
38391 // this.el.on("mousedown", this.onTabMouseDown, this);
38392 this.el.on("click", this.onTabClick, this);
38394 if(config.closable){
38395 var c = Roo.get(els.close, true);
38396 c.dom.title = this.closeText;
38397 c.addClassOnOver("close-over");
38398 c.on("click", this.closeClick, this);
38404 * Fires when this tab becomes the active tab.
38405 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38406 * @param {Roo.TabPanelItem} this
38410 * @event beforeclose
38411 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38412 * @param {Roo.TabPanelItem} this
38413 * @param {Object} e Set cancel to true on this object to cancel the close.
38415 "beforeclose": true,
38418 * Fires when this tab is closed.
38419 * @param {Roo.TabPanelItem} this
38423 * @event deactivate
38424 * Fires when this tab is no longer the active tab.
38425 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38426 * @param {Roo.TabPanelItem} this
38428 "deactivate" : true
38430 this.hidden = false;
38432 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38435 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38437 purgeListeners : function(){
38438 Roo.util.Observable.prototype.purgeListeners.call(this);
38439 this.el.removeAllListeners();
38442 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38445 this.pnode.addClass("active");
38448 this.tabPanel.stripWrap.repaint();
38450 this.fireEvent("activate", this.tabPanel, this);
38454 * Returns true if this tab is the active tab.
38455 * @return {Boolean}
38457 isActive : function(){
38458 return this.tabPanel.getActiveTab() == this;
38462 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38465 this.pnode.removeClass("active");
38467 this.fireEvent("deactivate", this.tabPanel, this);
38470 hideAction : function(){
38471 this.bodyEl.hide();
38472 this.bodyEl.setStyle("position", "absolute");
38473 this.bodyEl.setLeft("-20000px");
38474 this.bodyEl.setTop("-20000px");
38477 showAction : function(){
38478 this.bodyEl.setStyle("position", "relative");
38479 this.bodyEl.setTop("");
38480 this.bodyEl.setLeft("");
38481 this.bodyEl.show();
38485 * Set the tooltip for the tab.
38486 * @param {String} tooltip The tab's tooltip
38488 setTooltip : function(text){
38489 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38490 this.textEl.dom.qtip = text;
38491 this.textEl.dom.removeAttribute('title');
38493 this.textEl.dom.title = text;
38497 onTabClick : function(e){
38498 e.preventDefault();
38499 this.tabPanel.activate(this.id);
38502 onTabMouseDown : function(e){
38503 e.preventDefault();
38504 this.tabPanel.activate(this.id);
38507 getWidth : function(){
38508 return this.inner.getWidth();
38511 setWidth : function(width){
38512 var iwidth = width - this.pnode.getPadding("lr");
38513 this.inner.setWidth(iwidth);
38514 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38515 this.pnode.setWidth(width);
38519 * Show or hide the tab
38520 * @param {Boolean} hidden True to hide or false to show.
38522 setHidden : function(hidden){
38523 this.hidden = hidden;
38524 this.pnode.setStyle("display", hidden ? "none" : "");
38528 * Returns true if this tab is "hidden"
38529 * @return {Boolean}
38531 isHidden : function(){
38532 return this.hidden;
38536 * Returns the text for this tab
38539 getText : function(){
38543 autoSize : function(){
38544 //this.el.beginMeasure();
38545 this.textEl.setWidth(1);
38547 * #2804 [new] Tabs in Roojs
38548 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38550 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38551 //this.el.endMeasure();
38555 * Sets the text for the tab (Note: this also sets the tooltip text)
38556 * @param {String} text The tab's text and tooltip
38558 setText : function(text){
38560 this.textEl.update(text);
38561 this.setTooltip(text);
38562 //if(!this.tabPanel.resizeTabs){
38563 // this.autoSize();
38567 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38569 activate : function(){
38570 this.tabPanel.activate(this.id);
38574 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38576 disable : function(){
38577 if(this.tabPanel.active != this){
38578 this.disabled = true;
38579 this.pnode.addClass("disabled");
38584 * Enables this TabPanelItem if it was previously disabled.
38586 enable : function(){
38587 this.disabled = false;
38588 this.pnode.removeClass("disabled");
38592 * Sets the content for this TabPanelItem.
38593 * @param {String} content The content
38594 * @param {Boolean} loadScripts true to look for and load scripts
38596 setContent : function(content, loadScripts){
38597 this.bodyEl.update(content, loadScripts);
38601 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38602 * @return {Roo.UpdateManager} The UpdateManager
38604 getUpdateManager : function(){
38605 return this.bodyEl.getUpdateManager();
38609 * Set a URL to be used to load the content for this TabPanelItem.
38610 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38611 * @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)
38612 * @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)
38613 * @return {Roo.UpdateManager} The UpdateManager
38615 setUrl : function(url, params, loadOnce){
38616 if(this.refreshDelegate){
38617 this.un('activate', this.refreshDelegate);
38619 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38620 this.on("activate", this.refreshDelegate);
38621 return this.bodyEl.getUpdateManager();
38625 _handleRefresh : function(url, params, loadOnce){
38626 if(!loadOnce || !this.loaded){
38627 var updater = this.bodyEl.getUpdateManager();
38628 updater.update(url, params, this._setLoaded.createDelegate(this));
38633 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38634 * Will fail silently if the setUrl method has not been called.
38635 * This does not activate the panel, just updates its content.
38637 refresh : function(){
38638 if(this.refreshDelegate){
38639 this.loaded = false;
38640 this.refreshDelegate();
38645 _setLoaded : function(){
38646 this.loaded = true;
38650 closeClick : function(e){
38653 this.fireEvent("beforeclose", this, o);
38654 if(o.cancel !== true){
38655 this.tabPanel.removeTab(this.id);
38659 * The text displayed in the tooltip for the close icon.
38662 closeText : "Close this tab"
38665 * This script refer to:
38666 * Title: International Telephone Input
38667 * Author: Jack O'Connor
38668 * Code version: v12.1.12
38669 * Availability: https://github.com/jackocnr/intl-tel-input.git
38672 Roo.bootstrap.PhoneInputData = function() {
38675 "Afghanistan (افغانستان)",
38680 "Albania (Shqipëri)",
38685 "Algeria (الجزائر)",
38710 "Antigua and Barbuda",
38720 "Armenia (Հայաստան)",
38736 "Austria (Österreich)",
38741 "Azerbaijan (Azərbaycan)",
38751 "Bahrain (البحرين)",
38756 "Bangladesh (বাংলাদেশ)",
38766 "Belarus (Беларусь)",
38771 "Belgium (België)",
38801 "Bosnia and Herzegovina (Босна и Херцеговина)",
38816 "British Indian Ocean Territory",
38821 "British Virgin Islands",
38831 "Bulgaria (България)",
38841 "Burundi (Uburundi)",
38846 "Cambodia (កម្ពុជា)",
38851 "Cameroon (Cameroun)",
38860 ["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"]
38863 "Cape Verde (Kabu Verdi)",
38868 "Caribbean Netherlands",
38879 "Central African Republic (République centrafricaine)",
38899 "Christmas Island",
38905 "Cocos (Keeling) Islands",
38916 "Comoros (جزر القمر)",
38921 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38926 "Congo (Republic) (Congo-Brazzaville)",
38946 "Croatia (Hrvatska)",
38967 "Czech Republic (Česká republika)",
38972 "Denmark (Danmark)",
38987 "Dominican Republic (República Dominicana)",
38991 ["809", "829", "849"]
39009 "Equatorial Guinea (Guinea Ecuatorial)",
39029 "Falkland Islands (Islas Malvinas)",
39034 "Faroe Islands (Føroyar)",
39055 "French Guiana (Guyane française)",
39060 "French Polynesia (Polynésie française)",
39075 "Georgia (საქართველო)",
39080 "Germany (Deutschland)",
39100 "Greenland (Kalaallit Nunaat)",
39137 "Guinea-Bissau (Guiné Bissau)",
39162 "Hungary (Magyarország)",
39167 "Iceland (Ísland)",
39187 "Iraq (العراق)",
39203 "Israel (ישראל)",
39230 "Jordan (الأردن)",
39235 "Kazakhstan (Казахстан)",
39256 "Kuwait (الكويت)",
39261 "Kyrgyzstan (Кыргызстан)",
39271 "Latvia (Latvija)",
39276 "Lebanon (لبنان)",
39291 "Libya (ليبيا)",
39301 "Lithuania (Lietuva)",
39316 "Macedonia (FYROM) (Македонија)",
39321 "Madagascar (Madagasikara)",
39351 "Marshall Islands",
39361 "Mauritania (موريتانيا)",
39366 "Mauritius (Moris)",
39387 "Moldova (Republica Moldova)",
39397 "Mongolia (Монгол)",
39402 "Montenegro (Crna Gora)",
39412 "Morocco (المغرب)",
39418 "Mozambique (Moçambique)",
39423 "Myanmar (Burma) (မြန်မာ)",
39428 "Namibia (Namibië)",
39443 "Netherlands (Nederland)",
39448 "New Caledonia (Nouvelle-Calédonie)",
39483 "North Korea (조선 민주주의 인민 공화국)",
39488 "Northern Mariana Islands",
39504 "Pakistan (پاکستان)",
39514 "Palestine (فلسطين)",
39524 "Papua New Guinea",
39566 "Réunion (La Réunion)",
39572 "Romania (România)",
39588 "Saint Barthélemy",
39599 "Saint Kitts and Nevis",
39609 "Saint Martin (Saint-Martin (partie française))",
39615 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39620 "Saint Vincent and the Grenadines",
39635 "São Tomé and Príncipe (São Tomé e Príncipe)",
39640 "Saudi Arabia (المملكة العربية السعودية)",
39645 "Senegal (Sénégal)",
39675 "Slovakia (Slovensko)",
39680 "Slovenia (Slovenija)",
39690 "Somalia (Soomaaliya)",
39700 "South Korea (대한민국)",
39705 "South Sudan (جنوب السودان)",
39715 "Sri Lanka (ශ්රී ලංකාව)",
39720 "Sudan (السودان)",
39730 "Svalbard and Jan Mayen",
39741 "Sweden (Sverige)",
39746 "Switzerland (Schweiz)",
39751 "Syria (سوريا)",
39796 "Trinidad and Tobago",
39801 "Tunisia (تونس)",
39806 "Turkey (Türkiye)",
39816 "Turks and Caicos Islands",
39826 "U.S. Virgin Islands",
39836 "Ukraine (Україна)",
39841 "United Arab Emirates (الإمارات العربية المتحدة)",
39863 "Uzbekistan (Oʻzbekiston)",
39873 "Vatican City (Città del Vaticano)",
39884 "Vietnam (Việt Nam)",
39889 "Wallis and Futuna (Wallis-et-Futuna)",
39894 "Western Sahara (الصحراء الغربية)",
39900 "Yemen (اليمن)",
39924 * This script refer to:
39925 * Title: International Telephone Input
39926 * Author: Jack O'Connor
39927 * Code version: v12.1.12
39928 * Availability: https://github.com/jackocnr/intl-tel-input.git
39932 * @class Roo.bootstrap.PhoneInput
39933 * @extends Roo.bootstrap.TriggerField
39934 * An input with International dial-code selection
39936 * @cfg {String} defaultDialCode default '+852'
39937 * @cfg {Array} preferedCountries default []
39940 * Create a new PhoneInput.
39941 * @param {Object} config Configuration options
39944 Roo.bootstrap.PhoneInput = function(config) {
39945 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39948 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39950 listWidth: undefined,
39952 selectedClass: 'active',
39954 invalidClass : "has-warning",
39956 validClass: 'has-success',
39958 allowed: '0123456789',
39963 * @cfg {String} defaultDialCode The default dial code when initializing the input
39965 defaultDialCode: '+852',
39968 * @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
39970 preferedCountries: false,
39972 getAutoCreate : function()
39974 var data = Roo.bootstrap.PhoneInputData();
39975 var align = this.labelAlign || this.parentLabelAlign();
39978 this.allCountries = [];
39979 this.dialCodeMapping = [];
39981 for (var i = 0; i < data.length; i++) {
39983 this.allCountries[i] = {
39987 priority: c[3] || 0,
39988 areaCodes: c[4] || null
39990 this.dialCodeMapping[c[2]] = {
39993 priority: c[3] || 0,
39994 areaCodes: c[4] || null
40006 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40007 maxlength: this.max_length,
40008 cls : 'form-control tel-input',
40009 autocomplete: 'new-password'
40012 var hiddenInput = {
40015 cls: 'hidden-tel-input'
40019 hiddenInput.name = this.name;
40022 if (this.disabled) {
40023 input.disabled = true;
40026 var flag_container = {
40043 cls: this.hasFeedback ? 'has-feedback' : '',
40049 cls: 'dial-code-holder',
40056 cls: 'roo-select2-container input-group',
40063 if (this.fieldLabel.length) {
40066 tooltip: 'This field is required'
40072 cls: 'control-label',
40078 html: this.fieldLabel
40081 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40087 if(this.indicatorpos == 'right') {
40088 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40095 if(align == 'left') {
40103 if(this.labelWidth > 12){
40104 label.style = "width: " + this.labelWidth + 'px';
40106 if(this.labelWidth < 13 && this.labelmd == 0){
40107 this.labelmd = this.labelWidth;
40109 if(this.labellg > 0){
40110 label.cls += ' col-lg-' + this.labellg;
40111 input.cls += ' col-lg-' + (12 - this.labellg);
40113 if(this.labelmd > 0){
40114 label.cls += ' col-md-' + this.labelmd;
40115 container.cls += ' col-md-' + (12 - this.labelmd);
40117 if(this.labelsm > 0){
40118 label.cls += ' col-sm-' + this.labelsm;
40119 container.cls += ' col-sm-' + (12 - this.labelsm);
40121 if(this.labelxs > 0){
40122 label.cls += ' col-xs-' + this.labelxs;
40123 container.cls += ' col-xs-' + (12 - this.labelxs);
40133 var settings = this;
40135 ['xs','sm','md','lg'].map(function(size){
40136 if (settings[size]) {
40137 cfg.cls += ' col-' + size + '-' + settings[size];
40141 this.store = new Roo.data.Store({
40142 proxy : new Roo.data.MemoryProxy({}),
40143 reader : new Roo.data.JsonReader({
40154 'name' : 'dialCode',
40158 'name' : 'priority',
40162 'name' : 'areaCodes',
40169 if(!this.preferedCountries) {
40170 this.preferedCountries = [
40177 var p = this.preferedCountries.reverse();
40180 for (var i = 0; i < p.length; i++) {
40181 for (var j = 0; j < this.allCountries.length; j++) {
40182 if(this.allCountries[j].iso2 == p[i]) {
40183 var t = this.allCountries[j];
40184 this.allCountries.splice(j,1);
40185 this.allCountries.unshift(t);
40191 this.store.proxy.data = {
40193 data: this.allCountries
40199 initEvents : function()
40202 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40204 this.indicator = this.indicatorEl();
40205 this.flag = this.flagEl();
40206 this.dialCodeHolder = this.dialCodeHolderEl();
40208 this.trigger = this.el.select('div.flag-box',true).first();
40209 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40214 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40215 _this.list.setWidth(lw);
40218 this.list.on('mouseover', this.onViewOver, this);
40219 this.list.on('mousemove', this.onViewMove, this);
40220 this.inputEl().on("keyup", this.onKeyUp, this);
40221 this.inputEl().on("keypress", this.onKeyPress, this);
40223 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40225 this.view = new Roo.View(this.list, this.tpl, {
40226 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40229 this.view.on('click', this.onViewClick, this);
40230 this.setValue(this.defaultDialCode);
40233 onTriggerClick : function(e)
40235 Roo.log('trigger click');
40240 if(this.isExpanded()){
40242 this.hasFocus = false;
40244 this.store.load({});
40245 this.hasFocus = true;
40250 isExpanded : function()
40252 return this.list.isVisible();
40255 collapse : function()
40257 if(!this.isExpanded()){
40261 Roo.get(document).un('mousedown', this.collapseIf, this);
40262 Roo.get(document).un('mousewheel', this.collapseIf, this);
40263 this.fireEvent('collapse', this);
40267 expand : function()
40271 if(this.isExpanded() || !this.hasFocus){
40275 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40276 this.list.setWidth(lw);
40279 this.restrictHeight();
40281 Roo.get(document).on('mousedown', this.collapseIf, this);
40282 Roo.get(document).on('mousewheel', this.collapseIf, this);
40284 this.fireEvent('expand', this);
40287 restrictHeight : function()
40289 this.list.alignTo(this.inputEl(), this.listAlign);
40290 this.list.alignTo(this.inputEl(), this.listAlign);
40293 onViewOver : function(e, t)
40295 if(this.inKeyMode){
40298 var item = this.view.findItemFromChild(t);
40301 var index = this.view.indexOf(item);
40302 this.select(index, false);
40307 onViewClick : function(view, doFocus, el, e)
40309 var index = this.view.getSelectedIndexes()[0];
40311 var r = this.store.getAt(index);
40314 this.onSelect(r, index);
40316 if(doFocus !== false && !this.blockFocus){
40317 this.inputEl().focus();
40321 onViewMove : function(e, t)
40323 this.inKeyMode = false;
40326 select : function(index, scrollIntoView)
40328 this.selectedIndex = index;
40329 this.view.select(index);
40330 if(scrollIntoView !== false){
40331 var el = this.view.getNode(index);
40333 this.list.scrollChildIntoView(el, false);
40338 createList : function()
40340 this.list = Roo.get(document.body).createChild({
40342 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40343 style: 'display:none'
40346 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40349 collapseIf : function(e)
40351 var in_combo = e.within(this.el);
40352 var in_list = e.within(this.list);
40353 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40355 if (in_combo || in_list || is_list) {
40361 onSelect : function(record, index)
40363 if(this.fireEvent('beforeselect', this, record, index) !== false){
40365 this.setFlagClass(record.data.iso2);
40366 this.setDialCode(record.data.dialCode);
40367 this.hasFocus = false;
40369 this.fireEvent('select', this, record, index);
40373 flagEl : function()
40375 var flag = this.el.select('div.flag',true).first();
40382 dialCodeHolderEl : function()
40384 var d = this.el.select('input.dial-code-holder',true).first();
40391 setDialCode : function(v)
40393 this.dialCodeHolder.dom.value = '+'+v;
40396 setFlagClass : function(n)
40398 this.flag.dom.className = 'flag '+n;
40401 getValue : function()
40403 var v = this.inputEl().getValue();
40404 if(this.dialCodeHolder) {
40405 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40410 setValue : function(v)
40412 var d = this.getDialCode(v);
40414 //invalid dial code
40415 if(v.length == 0 || !d || d.length == 0) {
40417 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40418 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40424 this.setFlagClass(this.dialCodeMapping[d].iso2);
40425 this.setDialCode(d);
40426 this.inputEl().dom.value = v.replace('+'+d,'');
40427 this.hiddenEl().dom.value = this.getValue();
40432 getDialCode : function(v)
40436 if (v.length == 0) {
40437 return this.dialCodeHolder.dom.value;
40441 if (v.charAt(0) != "+") {
40444 var numericChars = "";
40445 for (var i = 1; i < v.length; i++) {
40446 var c = v.charAt(i);
40449 if (this.dialCodeMapping[numericChars]) {
40450 dialCode = v.substr(1, i);
40452 if (numericChars.length == 4) {
40462 this.setValue(this.defaultDialCode);
40466 hiddenEl : function()
40468 return this.el.select('input.hidden-tel-input',true).first();
40471 // after setting val
40472 onKeyUp : function(e){
40473 this.setValue(this.getValue());
40476 onKeyPress : function(e){
40477 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40484 * @class Roo.bootstrap.MoneyField
40485 * @extends Roo.bootstrap.ComboBox
40486 * Bootstrap MoneyField class
40489 * Create a new MoneyField.
40490 * @param {Object} config Configuration options
40493 Roo.bootstrap.MoneyField = function(config) {
40495 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40499 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40502 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40504 allowDecimals : true,
40506 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40508 decimalSeparator : ".",
40510 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40512 decimalPrecision : 0,
40514 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40516 allowNegative : true,
40518 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40522 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40524 minValue : Number.NEGATIVE_INFINITY,
40526 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40528 maxValue : Number.MAX_VALUE,
40530 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40532 minText : "The minimum value for this field is {0}",
40534 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40536 maxText : "The maximum value for this field is {0}",
40538 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40539 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40541 nanText : "{0} is not a valid number",
40543 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40547 * @cfg {String} defaults currency of the MoneyField
40548 * value should be in lkey
40550 defaultCurrency : false,
40552 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40554 thousandsDelimiter : false,
40556 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40567 getAutoCreate : function()
40569 var align = this.labelAlign || this.parentLabelAlign();
40581 cls : 'form-control roo-money-amount-input',
40582 autocomplete: 'new-password'
40585 var hiddenInput = {
40589 cls: 'hidden-number-input'
40592 if(this.max_length) {
40593 input.maxlength = this.max_length;
40597 hiddenInput.name = this.name;
40600 if (this.disabled) {
40601 input.disabled = true;
40604 var clg = 12 - this.inputlg;
40605 var cmd = 12 - this.inputmd;
40606 var csm = 12 - this.inputsm;
40607 var cxs = 12 - this.inputxs;
40611 cls : 'row roo-money-field',
40615 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40619 cls: 'roo-select2-container input-group',
40623 cls : 'form-control roo-money-currency-input',
40624 autocomplete: 'new-password',
40626 name : this.currencyName
40630 cls : 'input-group-addon',
40644 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40648 cls: this.hasFeedback ? 'has-feedback' : '',
40659 if (this.fieldLabel.length) {
40662 tooltip: 'This field is required'
40668 cls: 'control-label',
40674 html: this.fieldLabel
40677 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40683 if(this.indicatorpos == 'right') {
40684 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40691 if(align == 'left') {
40699 if(this.labelWidth > 12){
40700 label.style = "width: " + this.labelWidth + 'px';
40702 if(this.labelWidth < 13 && this.labelmd == 0){
40703 this.labelmd = this.labelWidth;
40705 if(this.labellg > 0){
40706 label.cls += ' col-lg-' + this.labellg;
40707 input.cls += ' col-lg-' + (12 - this.labellg);
40709 if(this.labelmd > 0){
40710 label.cls += ' col-md-' + this.labelmd;
40711 container.cls += ' col-md-' + (12 - this.labelmd);
40713 if(this.labelsm > 0){
40714 label.cls += ' col-sm-' + this.labelsm;
40715 container.cls += ' col-sm-' + (12 - this.labelsm);
40717 if(this.labelxs > 0){
40718 label.cls += ' col-xs-' + this.labelxs;
40719 container.cls += ' col-xs-' + (12 - this.labelxs);
40730 var settings = this;
40732 ['xs','sm','md','lg'].map(function(size){
40733 if (settings[size]) {
40734 cfg.cls += ' col-' + size + '-' + settings[size];
40741 initEvents : function()
40743 this.indicator = this.indicatorEl();
40745 this.initCurrencyEvent();
40747 this.initNumberEvent();
40750 initCurrencyEvent : function()
40753 throw "can not find store for combo";
40756 this.store = Roo.factory(this.store, Roo.data);
40757 this.store.parent = this;
40761 this.triggerEl = this.el.select('.input-group-addon', true).first();
40763 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40768 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40769 _this.list.setWidth(lw);
40772 this.list.on('mouseover', this.onViewOver, this);
40773 this.list.on('mousemove', this.onViewMove, this);
40774 this.list.on('scroll', this.onViewScroll, this);
40777 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40780 this.view = new Roo.View(this.list, this.tpl, {
40781 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40784 this.view.on('click', this.onViewClick, this);
40786 this.store.on('beforeload', this.onBeforeLoad, this);
40787 this.store.on('load', this.onLoad, this);
40788 this.store.on('loadexception', this.onLoadException, this);
40790 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40791 "up" : function(e){
40792 this.inKeyMode = true;
40796 "down" : function(e){
40797 if(!this.isExpanded()){
40798 this.onTriggerClick();
40800 this.inKeyMode = true;
40805 "enter" : function(e){
40808 if(this.fireEvent("specialkey", this, e)){
40809 this.onViewClick(false);
40815 "esc" : function(e){
40819 "tab" : function(e){
40822 if(this.fireEvent("specialkey", this, e)){
40823 this.onViewClick(false);
40831 doRelay : function(foo, bar, hname){
40832 if(hname == 'down' || this.scope.isExpanded()){
40833 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40841 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40845 initNumberEvent : function(e)
40847 this.inputEl().on("keydown" , this.fireKey, this);
40848 this.inputEl().on("focus", this.onFocus, this);
40849 this.inputEl().on("blur", this.onBlur, this);
40851 this.inputEl().relayEvent('keyup', this);
40853 if(this.indicator){
40854 this.indicator.addClass('invisible');
40857 this.originalValue = this.getValue();
40859 if(this.validationEvent == 'keyup'){
40860 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40861 this.inputEl().on('keyup', this.filterValidation, this);
40863 else if(this.validationEvent !== false){
40864 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40867 if(this.selectOnFocus){
40868 this.on("focus", this.preFocus, this);
40871 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40872 this.inputEl().on("keypress", this.filterKeys, this);
40874 this.inputEl().relayEvent('keypress', this);
40877 var allowed = "0123456789";
40879 if(this.allowDecimals){
40880 allowed += this.decimalSeparator;
40883 if(this.allowNegative){
40887 if(this.thousandsDelimiter) {
40891 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40893 var keyPress = function(e){
40895 var k = e.getKey();
40897 var c = e.getCharCode();
40900 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40901 allowed.indexOf(String.fromCharCode(c)) === -1
40907 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40911 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40916 this.inputEl().on("keypress", keyPress, this);
40920 onTriggerClick : function(e)
40927 this.loadNext = false;
40929 if(this.isExpanded()){
40934 this.hasFocus = true;
40936 if(this.triggerAction == 'all') {
40937 this.doQuery(this.allQuery, true);
40941 this.doQuery(this.getRawValue());
40944 getCurrency : function()
40946 var v = this.currencyEl().getValue();
40951 restrictHeight : function()
40953 this.list.alignTo(this.currencyEl(), this.listAlign);
40954 this.list.alignTo(this.currencyEl(), this.listAlign);
40957 onViewClick : function(view, doFocus, el, e)
40959 var index = this.view.getSelectedIndexes()[0];
40961 var r = this.store.getAt(index);
40964 this.onSelect(r, index);
40968 onSelect : function(record, index){
40970 if(this.fireEvent('beforeselect', this, record, index) !== false){
40972 this.setFromCurrencyData(index > -1 ? record.data : false);
40976 this.fireEvent('select', this, record, index);
40980 setFromCurrencyData : function(o)
40984 this.lastCurrency = o;
40986 if (this.currencyField) {
40987 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40989 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
40992 this.lastSelectionText = currency;
40994 //setting default currency
40995 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40996 this.setCurrency(this.defaultCurrency);
41000 this.setCurrency(currency);
41003 setFromData : function(o)
41007 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41009 this.setFromCurrencyData(c);
41014 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41016 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41019 this.setValue(value);
41023 setCurrency : function(v)
41025 this.currencyValue = v;
41028 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41033 setValue : function(v)
41035 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41041 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41043 this.inputEl().dom.value = (v == '') ? '' :
41044 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41046 if(!this.allowZero && v === '0') {
41047 this.hiddenEl().dom.value = '';
41048 this.inputEl().dom.value = '';
41055 getRawValue : function()
41057 var v = this.inputEl().getValue();
41062 getValue : function()
41064 return this.fixPrecision(this.parseValue(this.getRawValue()));
41067 parseValue : function(value)
41069 if(this.thousandsDelimiter) {
41071 r = new RegExp(",", "g");
41072 value = value.replace(r, "");
41075 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41076 return isNaN(value) ? '' : value;
41080 fixPrecision : function(value)
41082 if(this.thousandsDelimiter) {
41084 r = new RegExp(",", "g");
41085 value = value.replace(r, "");
41088 var nan = isNaN(value);
41090 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41091 return nan ? '' : value;
41093 return parseFloat(value).toFixed(this.decimalPrecision);
41096 decimalPrecisionFcn : function(v)
41098 return Math.floor(v);
41101 validateValue : function(value)
41103 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41107 var num = this.parseValue(value);
41110 this.markInvalid(String.format(this.nanText, value));
41114 if(num < this.minValue){
41115 this.markInvalid(String.format(this.minText, this.minValue));
41119 if(num > this.maxValue){
41120 this.markInvalid(String.format(this.maxText, this.maxValue));
41127 validate : function()
41129 if(this.disabled || this.allowBlank){
41134 var currency = this.getCurrency();
41136 if(this.validateValue(this.getRawValue()) && currency.length){
41141 this.markInvalid();
41145 getName: function()
41150 beforeBlur : function()
41156 var v = this.parseValue(this.getRawValue());
41163 onBlur : function()
41167 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41168 //this.el.removeClass(this.focusClass);
41171 this.hasFocus = false;
41173 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41177 var v = this.getValue();
41179 if(String(v) !== String(this.startValue)){
41180 this.fireEvent('change', this, v, this.startValue);
41183 this.fireEvent("blur", this);
41186 inputEl : function()
41188 return this.el.select('.roo-money-amount-input', true).first();
41191 currencyEl : function()
41193 return this.el.select('.roo-money-currency-input', true).first();
41196 hiddenEl : function()
41198 return this.el.select('input.hidden-number-input',true).first();