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',
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-' +
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-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-' +
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);
9160 if (align ==='left' && this.fieldLabel.length) {
9162 cfg.cls += ' roo-form-group-label-left';
9167 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9168 tooltip : 'This field is required'
9173 cls : 'control-label',
9174 html : this.fieldLabel
9185 var labelCfg = cfg.cn[1];
9186 var contentCfg = cfg.cn[2];
9188 if(this.indicatorpos == 'right'){
9193 cls : 'control-label',
9197 html : this.fieldLabel
9201 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9202 tooltip : 'This field is required'
9215 labelCfg = cfg.cn[0];
9216 contentCfg = cfg.cn[1];
9220 if(this.labelWidth > 12){
9221 labelCfg.style = "width: " + this.labelWidth + 'px';
9224 if(this.labelWidth < 13 && this.labelmd == 0){
9225 this.labelmd = this.labelWidth;
9228 if(this.labellg > 0){
9229 labelCfg.cls += ' col-lg-' + this.labellg;
9230 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9233 if(this.labelmd > 0){
9234 labelCfg.cls += ' col-md-' + this.labelmd;
9235 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9238 if(this.labelsm > 0){
9239 labelCfg.cls += ' col-sm-' + this.labelsm;
9240 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9243 if(this.labelxs > 0){
9244 labelCfg.cls += ' col-xs-' + this.labelxs;
9245 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9249 } else if ( this.fieldLabel.length) {
9254 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9255 tooltip : 'This field is required'
9259 //cls : 'input-group-addon',
9260 html : this.fieldLabel
9268 if(this.indicatorpos == 'right'){
9273 //cls : 'input-group-addon',
9274 html : this.fieldLabel
9279 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9280 tooltip : 'This field is required'
9300 if (this.parentType === 'Navbar' && this.parent().bar) {
9301 cfg.cls += ' navbar-form';
9304 if (this.parentType === 'NavGroup') {
9305 cfg.cls += ' navbar-form';
9313 * return the real input element.
9315 inputEl: function ()
9317 return this.el.select('input.form-control',true).first();
9320 tooltipEl : function()
9322 return this.inputEl();
9325 indicatorEl : function()
9327 var indicator = this.el.select('i.roo-required-indicator',true).first();
9337 setDisabled : function(v)
9339 var i = this.inputEl().dom;
9341 i.removeAttribute('disabled');
9345 i.setAttribute('disabled','true');
9347 initEvents : function()
9350 this.inputEl().on("keydown" , this.fireKey, this);
9351 this.inputEl().on("focus", this.onFocus, this);
9352 this.inputEl().on("blur", this.onBlur, this);
9354 this.inputEl().relayEvent('keyup', this);
9356 this.indicator = this.indicatorEl();
9359 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9362 // reference to original value for reset
9363 this.originalValue = this.getValue();
9364 //Roo.form.TextField.superclass.initEvents.call(this);
9365 if(this.validationEvent == 'keyup'){
9366 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9367 this.inputEl().on('keyup', this.filterValidation, this);
9369 else if(this.validationEvent !== false){
9370 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9373 if(this.selectOnFocus){
9374 this.on("focus", this.preFocus, this);
9377 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9378 this.inputEl().on("keypress", this.filterKeys, this);
9380 this.inputEl().relayEvent('keypress', this);
9383 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9384 this.el.on("click", this.autoSize, this);
9387 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9388 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9391 if (typeof(this.before) == 'object') {
9392 this.before.render(this.el.select('.roo-input-before',true).first());
9394 if (typeof(this.after) == 'object') {
9395 this.after.render(this.el.select('.roo-input-after',true).first());
9398 this.inputEl().on('change', this.onChange, this);
9401 filterValidation : function(e){
9402 if(!e.isNavKeyPress()){
9403 this.validationTask.delay(this.validationDelay);
9407 * Validates the field value
9408 * @return {Boolean} True if the value is valid, else false
9410 validate : function(){
9411 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9412 if(this.disabled || this.validateValue(this.getRawValue())){
9423 * Validates a value according to the field's validation rules and marks the field as invalid
9424 * if the validation fails
9425 * @param {Mixed} value The value to validate
9426 * @return {Boolean} True if the value is valid, else false
9428 validateValue : function(value)
9430 if(this.getVisibilityEl().hasClass('hidden')){
9434 if(value.length < 1) { // if it's blank
9435 if(this.allowBlank){
9441 if(value.length < this.minLength){
9444 if(value.length > this.maxLength){
9448 var vt = Roo.form.VTypes;
9449 if(!vt[this.vtype](value, this)){
9453 if(typeof this.validator == "function"){
9454 var msg = this.validator(value);
9458 if (typeof(msg) == 'string') {
9459 this.invalidText = msg;
9463 if(this.regex && !this.regex.test(value)){
9471 fireKey : function(e){
9472 //Roo.log('field ' + e.getKey());
9473 if(e.isNavKeyPress()){
9474 this.fireEvent("specialkey", this, e);
9477 focus : function (selectText){
9479 this.inputEl().focus();
9480 if(selectText === true){
9481 this.inputEl().dom.select();
9487 onFocus : function(){
9488 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9489 // this.el.addClass(this.focusClass);
9492 this.hasFocus = true;
9493 this.startValue = this.getValue();
9494 this.fireEvent("focus", this);
9498 beforeBlur : Roo.emptyFn,
9502 onBlur : function(){
9504 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9505 //this.el.removeClass(this.focusClass);
9507 this.hasFocus = false;
9508 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9511 var v = this.getValue();
9512 if(String(v) !== String(this.startValue)){
9513 this.fireEvent('change', this, v, this.startValue);
9515 this.fireEvent("blur", this);
9518 onChange : function(e)
9520 var v = this.getValue();
9521 if(String(v) !== String(this.startValue)){
9522 this.fireEvent('change', this, v, this.startValue);
9528 * Resets the current field value to the originally loaded value and clears any validation messages
9531 this.setValue(this.originalValue);
9535 * Returns the name of the field
9536 * @return {Mixed} name The name field
9538 getName: function(){
9542 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9543 * @return {Mixed} value The field value
9545 getValue : function(){
9547 var v = this.inputEl().getValue();
9552 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9553 * @return {Mixed} value The field value
9555 getRawValue : function(){
9556 var v = this.inputEl().getValue();
9562 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9563 * @param {Mixed} value The value to set
9565 setRawValue : function(v){
9566 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9569 selectText : function(start, end){
9570 var v = this.getRawValue();
9572 start = start === undefined ? 0 : start;
9573 end = end === undefined ? v.length : end;
9574 var d = this.inputEl().dom;
9575 if(d.setSelectionRange){
9576 d.setSelectionRange(start, end);
9577 }else if(d.createTextRange){
9578 var range = d.createTextRange();
9579 range.moveStart("character", start);
9580 range.moveEnd("character", v.length-end);
9587 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9588 * @param {Mixed} value The value to set
9590 setValue : function(v){
9593 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9599 processValue : function(value){
9600 if(this.stripCharsRe){
9601 var newValue = value.replace(this.stripCharsRe, '');
9602 if(newValue !== value){
9603 this.setRawValue(newValue);
9610 preFocus : function(){
9612 if(this.selectOnFocus){
9613 this.inputEl().dom.select();
9616 filterKeys : function(e){
9618 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9621 var c = e.getCharCode(), cc = String.fromCharCode(c);
9622 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9625 if(!this.maskRe.test(cc)){
9630 * Clear any invalid styles/messages for this field
9632 clearInvalid : function(){
9634 if(!this.el || this.preventMark){ // not rendered
9639 this.el.removeClass(this.invalidClass);
9641 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9643 var feedback = this.el.select('.form-control-feedback', true).first();
9646 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9652 this.indicator.removeClass('visible');
9653 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9656 this.fireEvent('valid', this);
9660 * Mark this field as valid
9662 markValid : function()
9664 if(!this.el || this.preventMark){ // not rendered...
9668 this.el.removeClass([this.invalidClass, this.validClass]);
9670 var feedback = this.el.select('.form-control-feedback', true).first();
9673 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9677 this.indicator.removeClass('visible');
9678 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9685 if(this.allowBlank && !this.getRawValue().length){
9689 this.el.addClass(this.validClass);
9691 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9693 var feedback = this.el.select('.form-control-feedback', true).first();
9696 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9697 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9702 this.fireEvent('valid', this);
9706 * Mark this field as invalid
9707 * @param {String} msg The validation message
9709 markInvalid : function(msg)
9711 if(!this.el || this.preventMark){ // not rendered
9715 this.el.removeClass([this.invalidClass, this.validClass]);
9717 var feedback = this.el.select('.form-control-feedback', true).first();
9720 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9727 if(this.allowBlank && !this.getRawValue().length){
9732 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9733 this.indicator.addClass('visible');
9736 this.el.addClass(this.invalidClass);
9738 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9740 var feedback = this.el.select('.form-control-feedback', true).first();
9743 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9745 if(this.getValue().length || this.forceFeedback){
9746 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9753 this.fireEvent('invalid', this, msg);
9756 SafariOnKeyDown : function(event)
9758 // this is a workaround for a password hang bug on chrome/ webkit.
9759 if (this.inputEl().dom.type != 'password') {
9763 var isSelectAll = false;
9765 if(this.inputEl().dom.selectionEnd > 0){
9766 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9768 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9769 event.preventDefault();
9774 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9776 event.preventDefault();
9777 // this is very hacky as keydown always get's upper case.
9779 var cc = String.fromCharCode(event.getCharCode());
9780 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9784 adjustWidth : function(tag, w){
9785 tag = tag.toLowerCase();
9786 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9787 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9791 if(tag == 'textarea'){
9794 }else if(Roo.isOpera){
9798 if(tag == 'textarea'){
9806 setFieldLabel : function(v)
9813 var ar = this.el.select('label > span',true);
9815 if (ar.elements.length) {
9816 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9817 this.fieldLabel = v;
9821 var br = this.el.select('label',true);
9823 if(br.elements.length) {
9824 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9825 this.fieldLabel = v;
9829 Roo.log('Cannot Found any of label > span || label in input');
9833 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9834 this.fieldLabel = v;
9849 * @class Roo.bootstrap.TextArea
9850 * @extends Roo.bootstrap.Input
9851 * Bootstrap TextArea class
9852 * @cfg {Number} cols Specifies the visible width of a text area
9853 * @cfg {Number} rows Specifies the visible number of lines in a text area
9854 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9855 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9856 * @cfg {string} html text
9859 * Create a new TextArea
9860 * @param {Object} config The config object
9863 Roo.bootstrap.TextArea = function(config){
9864 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9868 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9878 getAutoCreate : function(){
9880 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9886 if(this.inputType != 'hidden'){
9887 cfg.cls = 'form-group' //input-group
9895 value : this.value || '',
9896 html: this.html || '',
9897 cls : 'form-control',
9898 placeholder : this.placeholder || ''
9902 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9903 input.maxLength = this.maxLength;
9907 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9911 input.cols = this.cols;
9914 if (this.readOnly) {
9915 input.readonly = true;
9919 input.name = this.name;
9923 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9927 ['xs','sm','md','lg'].map(function(size){
9928 if (settings[size]) {
9929 cfg.cls += ' col-' + size + '-' + settings[size];
9933 var inputblock = input;
9935 if(this.hasFeedback && !this.allowBlank){
9939 cls: 'glyphicon form-control-feedback'
9943 cls : 'has-feedback',
9952 if (this.before || this.after) {
9955 cls : 'input-group',
9959 inputblock.cn.push({
9961 cls : 'input-group-addon',
9966 inputblock.cn.push(input);
9968 if(this.hasFeedback && !this.allowBlank){
9969 inputblock.cls += ' has-feedback';
9970 inputblock.cn.push(feedback);
9974 inputblock.cn.push({
9976 cls : 'input-group-addon',
9983 if (align ==='left' && this.fieldLabel.length) {
9988 cls : 'control-label',
9989 html : this.fieldLabel
10000 if(this.labelWidth > 12){
10001 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10004 if(this.labelWidth < 13 && this.labelmd == 0){
10005 this.labelmd = this.labelWidth;
10008 if(this.labellg > 0){
10009 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10010 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10013 if(this.labelmd > 0){
10014 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10015 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10018 if(this.labelsm > 0){
10019 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10020 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10023 if(this.labelxs > 0){
10024 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10025 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10028 } else if ( this.fieldLabel.length) {
10033 //cls : 'input-group-addon',
10034 html : this.fieldLabel
10052 if (this.disabled) {
10053 input.disabled=true;
10060 * return the real textarea element.
10062 inputEl: function ()
10064 return this.el.select('textarea.form-control',true).first();
10068 * Clear any invalid styles/messages for this field
10070 clearInvalid : function()
10073 if(!this.el || this.preventMark){ // not rendered
10077 var label = this.el.select('label', true).first();
10078 var icon = this.el.select('i.fa-star', true).first();
10084 this.el.removeClass(this.invalidClass);
10086 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10088 var feedback = this.el.select('.form-control-feedback', true).first();
10091 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10096 this.fireEvent('valid', this);
10100 * Mark this field as valid
10102 markValid : function()
10104 if(!this.el || this.preventMark){ // not rendered
10108 this.el.removeClass([this.invalidClass, this.validClass]);
10110 var feedback = this.el.select('.form-control-feedback', true).first();
10113 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10116 if(this.disabled || this.allowBlank){
10120 var label = this.el.select('label', true).first();
10121 var icon = this.el.select('i.fa-star', true).first();
10127 this.el.addClass(this.validClass);
10129 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10131 var feedback = this.el.select('.form-control-feedback', true).first();
10134 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10135 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10140 this.fireEvent('valid', this);
10144 * Mark this field as invalid
10145 * @param {String} msg The validation message
10147 markInvalid : function(msg)
10149 if(!this.el || this.preventMark){ // not rendered
10153 this.el.removeClass([this.invalidClass, this.validClass]);
10155 var feedback = this.el.select('.form-control-feedback', true).first();
10158 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10161 if(this.disabled || this.allowBlank){
10165 var label = this.el.select('label', true).first();
10166 var icon = this.el.select('i.fa-star', true).first();
10168 if(!this.getValue().length && label && !icon){
10169 this.el.createChild({
10171 cls : 'text-danger fa fa-lg fa-star',
10172 tooltip : 'This field is required',
10173 style : 'margin-right:5px;'
10177 this.el.addClass(this.invalidClass);
10179 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10181 var feedback = this.el.select('.form-control-feedback', true).first();
10184 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10186 if(this.getValue().length || this.forceFeedback){
10187 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10194 this.fireEvent('invalid', this, msg);
10202 * trigger field - base class for combo..
10207 * @class Roo.bootstrap.TriggerField
10208 * @extends Roo.bootstrap.Input
10209 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10210 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10211 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10212 * for which you can provide a custom implementation. For example:
10214 var trigger = new Roo.bootstrap.TriggerField();
10215 trigger.onTriggerClick = myTriggerFn;
10216 trigger.applyTo('my-field');
10219 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10220 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10221 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10222 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10223 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10226 * Create a new TriggerField.
10227 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10228 * to the base TextField)
10230 Roo.bootstrap.TriggerField = function(config){
10231 this.mimicing = false;
10232 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10235 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10237 * @cfg {String} triggerClass A CSS class to apply to the trigger
10240 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10245 * @cfg {Boolean} removable (true|false) special filter default false
10249 /** @cfg {Boolean} grow @hide */
10250 /** @cfg {Number} growMin @hide */
10251 /** @cfg {Number} growMax @hide */
10257 autoSize: Roo.emptyFn,
10261 deferHeight : true,
10264 actionMode : 'wrap',
10269 getAutoCreate : function(){
10271 var align = this.labelAlign || this.parentLabelAlign();
10276 cls: 'form-group' //input-group
10283 type : this.inputType,
10284 cls : 'form-control',
10285 autocomplete: 'new-password',
10286 placeholder : this.placeholder || ''
10290 input.name = this.name;
10293 input.cls += ' input-' + this.size;
10296 if (this.disabled) {
10297 input.disabled=true;
10300 var inputblock = input;
10302 if(this.hasFeedback && !this.allowBlank){
10306 cls: 'glyphicon form-control-feedback'
10309 if(this.removable && !this.editable && !this.tickable){
10311 cls : 'has-feedback',
10317 cls : 'roo-combo-removable-btn close'
10324 cls : 'has-feedback',
10333 if(this.removable && !this.editable && !this.tickable){
10335 cls : 'roo-removable',
10341 cls : 'roo-combo-removable-btn close'
10348 if (this.before || this.after) {
10351 cls : 'input-group',
10355 inputblock.cn.push({
10357 cls : 'input-group-addon',
10362 inputblock.cn.push(input);
10364 if(this.hasFeedback && !this.allowBlank){
10365 inputblock.cls += ' has-feedback';
10366 inputblock.cn.push(feedback);
10370 inputblock.cn.push({
10372 cls : 'input-group-addon',
10385 cls: 'form-hidden-field'
10399 cls: 'form-hidden-field'
10403 cls: 'roo-select2-choices',
10407 cls: 'roo-select2-search-field',
10420 cls: 'roo-select2-container input-group',
10425 // cls: 'typeahead typeahead-long dropdown-menu',
10426 // style: 'display:none'
10431 if(!this.multiple && this.showToggleBtn){
10437 if (this.caret != false) {
10440 cls: 'fa fa-' + this.caret
10447 cls : 'input-group-addon btn dropdown-toggle',
10452 cls: 'combobox-clear',
10466 combobox.cls += ' roo-select2-container-multi';
10469 if (align ==='left' && this.fieldLabel.length) {
10471 cfg.cls += ' roo-form-group-label-left';
10476 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10477 tooltip : 'This field is required'
10482 cls : 'control-label',
10483 html : this.fieldLabel
10495 var labelCfg = cfg.cn[1];
10496 var contentCfg = cfg.cn[2];
10498 if(this.indicatorpos == 'right'){
10503 cls : 'control-label',
10507 html : this.fieldLabel
10511 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10512 tooltip : 'This field is required'
10525 labelCfg = cfg.cn[0];
10526 contentCfg = cfg.cn[1];
10529 if(this.labelWidth > 12){
10530 labelCfg.style = "width: " + this.labelWidth + 'px';
10533 if(this.labelWidth < 13 && this.labelmd == 0){
10534 this.labelmd = this.labelWidth;
10537 if(this.labellg > 0){
10538 labelCfg.cls += ' col-lg-' + this.labellg;
10539 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10542 if(this.labelmd > 0){
10543 labelCfg.cls += ' col-md-' + this.labelmd;
10544 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10547 if(this.labelsm > 0){
10548 labelCfg.cls += ' col-sm-' + this.labelsm;
10549 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10552 if(this.labelxs > 0){
10553 labelCfg.cls += ' col-xs-' + this.labelxs;
10554 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10557 } else if ( this.fieldLabel.length) {
10558 // Roo.log(" label");
10562 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10563 tooltip : 'This field is required'
10567 //cls : 'input-group-addon',
10568 html : this.fieldLabel
10576 if(this.indicatorpos == 'right'){
10584 html : this.fieldLabel
10588 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10589 tooltip : 'This field is required'
10602 // Roo.log(" no label && no align");
10609 ['xs','sm','md','lg'].map(function(size){
10610 if (settings[size]) {
10611 cfg.cls += ' col-' + size + '-' + settings[size];
10622 onResize : function(w, h){
10623 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10624 // if(typeof w == 'number'){
10625 // var x = w - this.trigger.getWidth();
10626 // this.inputEl().setWidth(this.adjustWidth('input', x));
10627 // this.trigger.setStyle('left', x+'px');
10632 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10635 getResizeEl : function(){
10636 return this.inputEl();
10640 getPositionEl : function(){
10641 return this.inputEl();
10645 alignErrorIcon : function(){
10646 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10650 initEvents : function(){
10654 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10655 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10656 if(!this.multiple && this.showToggleBtn){
10657 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10658 if(this.hideTrigger){
10659 this.trigger.setDisplayed(false);
10661 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10665 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10668 if(this.removable && !this.editable && !this.tickable){
10669 var close = this.closeTriggerEl();
10672 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10673 close.on('click', this.removeBtnClick, this, close);
10677 //this.trigger.addClassOnOver('x-form-trigger-over');
10678 //this.trigger.addClassOnClick('x-form-trigger-click');
10681 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10685 closeTriggerEl : function()
10687 var close = this.el.select('.roo-combo-removable-btn', true).first();
10688 return close ? close : false;
10691 removeBtnClick : function(e, h, el)
10693 e.preventDefault();
10695 if(this.fireEvent("remove", this) !== false){
10697 this.fireEvent("afterremove", this)
10701 createList : function()
10703 this.list = Roo.get(document.body).createChild({
10705 cls: 'typeahead typeahead-long dropdown-menu',
10706 style: 'display:none'
10709 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10714 initTrigger : function(){
10719 onDestroy : function(){
10721 this.trigger.removeAllListeners();
10722 // this.trigger.remove();
10725 // this.wrap.remove();
10727 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10731 onFocus : function(){
10732 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10734 if(!this.mimicing){
10735 this.wrap.addClass('x-trigger-wrap-focus');
10736 this.mimicing = true;
10737 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10738 if(this.monitorTab){
10739 this.el.on("keydown", this.checkTab, this);
10746 checkTab : function(e){
10747 if(e.getKey() == e.TAB){
10748 this.triggerBlur();
10753 onBlur : function(){
10758 mimicBlur : function(e, t){
10760 if(!this.wrap.contains(t) && this.validateBlur()){
10761 this.triggerBlur();
10767 triggerBlur : function(){
10768 this.mimicing = false;
10769 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10770 if(this.monitorTab){
10771 this.el.un("keydown", this.checkTab, this);
10773 //this.wrap.removeClass('x-trigger-wrap-focus');
10774 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10778 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10779 validateBlur : function(e, t){
10784 onDisable : function(){
10785 this.inputEl().dom.disabled = true;
10786 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10788 // this.wrap.addClass('x-item-disabled');
10793 onEnable : function(){
10794 this.inputEl().dom.disabled = false;
10795 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10797 // this.el.removeClass('x-item-disabled');
10802 onShow : function(){
10803 var ae = this.getActionEl();
10806 ae.dom.style.display = '';
10807 ae.dom.style.visibility = 'visible';
10813 onHide : function(){
10814 var ae = this.getActionEl();
10815 ae.dom.style.display = 'none';
10819 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10820 * by an implementing function.
10822 * @param {EventObject} e
10824 onTriggerClick : Roo.emptyFn
10828 * Ext JS Library 1.1.1
10829 * Copyright(c) 2006-2007, Ext JS, LLC.
10831 * Originally Released Under LGPL - original licence link has changed is not relivant.
10834 * <script type="text/javascript">
10839 * @class Roo.data.SortTypes
10841 * Defines the default sorting (casting?) comparison functions used when sorting data.
10843 Roo.data.SortTypes = {
10845 * Default sort that does nothing
10846 * @param {Mixed} s The value being converted
10847 * @return {Mixed} The comparison value
10849 none : function(s){
10854 * The regular expression used to strip tags
10858 stripTagsRE : /<\/?[^>]+>/gi,
10861 * Strips all HTML tags to sort on text only
10862 * @param {Mixed} s The value being converted
10863 * @return {String} The comparison value
10865 asText : function(s){
10866 return String(s).replace(this.stripTagsRE, "");
10870 * Strips all HTML tags to sort on text only - Case insensitive
10871 * @param {Mixed} s The value being converted
10872 * @return {String} The comparison value
10874 asUCText : function(s){
10875 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10879 * Case insensitive string
10880 * @param {Mixed} s The value being converted
10881 * @return {String} The comparison value
10883 asUCString : function(s) {
10884 return String(s).toUpperCase();
10889 * @param {Mixed} s The value being converted
10890 * @return {Number} The comparison value
10892 asDate : function(s) {
10896 if(s instanceof Date){
10897 return s.getTime();
10899 return Date.parse(String(s));
10904 * @param {Mixed} s The value being converted
10905 * @return {Float} The comparison value
10907 asFloat : function(s) {
10908 var val = parseFloat(String(s).replace(/,/g, ""));
10917 * @param {Mixed} s The value being converted
10918 * @return {Number} The comparison value
10920 asInt : function(s) {
10921 var val = parseInt(String(s).replace(/,/g, ""));
10929 * Ext JS Library 1.1.1
10930 * Copyright(c) 2006-2007, Ext JS, LLC.
10932 * Originally Released Under LGPL - original licence link has changed is not relivant.
10935 * <script type="text/javascript">
10939 * @class Roo.data.Record
10940 * Instances of this class encapsulate both record <em>definition</em> information, and record
10941 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10942 * to access Records cached in an {@link Roo.data.Store} object.<br>
10944 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10945 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10948 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10950 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10951 * {@link #create}. The parameters are the same.
10952 * @param {Array} data An associative Array of data values keyed by the field name.
10953 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10954 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10955 * not specified an integer id is generated.
10957 Roo.data.Record = function(data, id){
10958 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10963 * Generate a constructor for a specific record layout.
10964 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10965 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10966 * Each field definition object may contain the following properties: <ul>
10967 * <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,
10968 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10969 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10970 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10971 * is being used, then this is a string containing the javascript expression to reference the data relative to
10972 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10973 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10974 * this may be omitted.</p></li>
10975 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10976 * <ul><li>auto (Default, implies no conversion)</li>
10981 * <li>date</li></ul></p></li>
10982 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10983 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10984 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10985 * by the Reader into an object that will be stored in the Record. It is passed the
10986 * following parameters:<ul>
10987 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10989 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10991 * <br>usage:<br><pre><code>
10992 var TopicRecord = Roo.data.Record.create(
10993 {name: 'title', mapping: 'topic_title'},
10994 {name: 'author', mapping: 'username'},
10995 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10996 {name: 'lastPost', mapping: 'post_time', type: 'date'},
10997 {name: 'lastPoster', mapping: 'user2'},
10998 {name: 'excerpt', mapping: 'post_text'}
11001 var myNewRecord = new TopicRecord({
11002 title: 'Do my job please',
11005 lastPost: new Date(),
11006 lastPoster: 'Animal',
11007 excerpt: 'No way dude!'
11009 myStore.add(myNewRecord);
11014 Roo.data.Record.create = function(o){
11015 var f = function(){
11016 f.superclass.constructor.apply(this, arguments);
11018 Roo.extend(f, Roo.data.Record);
11019 var p = f.prototype;
11020 p.fields = new Roo.util.MixedCollection(false, function(field){
11023 for(var i = 0, len = o.length; i < len; i++){
11024 p.fields.add(new Roo.data.Field(o[i]));
11026 f.getField = function(name){
11027 return p.fields.get(name);
11032 Roo.data.Record.AUTO_ID = 1000;
11033 Roo.data.Record.EDIT = 'edit';
11034 Roo.data.Record.REJECT = 'reject';
11035 Roo.data.Record.COMMIT = 'commit';
11037 Roo.data.Record.prototype = {
11039 * Readonly flag - true if this record has been modified.
11048 join : function(store){
11049 this.store = store;
11053 * Set the named field to the specified value.
11054 * @param {String} name The name of the field to set.
11055 * @param {Object} value The value to set the field to.
11057 set : function(name, value){
11058 if(this.data[name] == value){
11062 if(!this.modified){
11063 this.modified = {};
11065 if(typeof this.modified[name] == 'undefined'){
11066 this.modified[name] = this.data[name];
11068 this.data[name] = value;
11069 if(!this.editing && this.store){
11070 this.store.afterEdit(this);
11075 * Get the value of the named field.
11076 * @param {String} name The name of the field to get the value of.
11077 * @return {Object} The value of the field.
11079 get : function(name){
11080 return this.data[name];
11084 beginEdit : function(){
11085 this.editing = true;
11086 this.modified = {};
11090 cancelEdit : function(){
11091 this.editing = false;
11092 delete this.modified;
11096 endEdit : function(){
11097 this.editing = false;
11098 if(this.dirty && this.store){
11099 this.store.afterEdit(this);
11104 * Usually called by the {@link Roo.data.Store} which owns the Record.
11105 * Rejects all changes made to the Record since either creation, or the last commit operation.
11106 * Modified fields are reverted to their original values.
11108 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11109 * of reject operations.
11111 reject : function(){
11112 var m = this.modified;
11114 if(typeof m[n] != "function"){
11115 this.data[n] = m[n];
11118 this.dirty = false;
11119 delete this.modified;
11120 this.editing = false;
11122 this.store.afterReject(this);
11127 * Usually called by the {@link Roo.data.Store} which owns the Record.
11128 * Commits all changes made to the Record since either creation, or the last commit operation.
11130 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11131 * of commit operations.
11133 commit : function(){
11134 this.dirty = false;
11135 delete this.modified;
11136 this.editing = false;
11138 this.store.afterCommit(this);
11143 hasError : function(){
11144 return this.error != null;
11148 clearError : function(){
11153 * Creates a copy of this record.
11154 * @param {String} id (optional) A new record id if you don't want to use this record's id
11157 copy : function(newId) {
11158 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11162 * Ext JS Library 1.1.1
11163 * Copyright(c) 2006-2007, Ext JS, LLC.
11165 * Originally Released Under LGPL - original licence link has changed is not relivant.
11168 * <script type="text/javascript">
11174 * @class Roo.data.Store
11175 * @extends Roo.util.Observable
11176 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11177 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11179 * 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
11180 * has no knowledge of the format of the data returned by the Proxy.<br>
11182 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11183 * instances from the data object. These records are cached and made available through accessor functions.
11185 * Creates a new Store.
11186 * @param {Object} config A config object containing the objects needed for the Store to access data,
11187 * and read the data into Records.
11189 Roo.data.Store = function(config){
11190 this.data = new Roo.util.MixedCollection(false);
11191 this.data.getKey = function(o){
11194 this.baseParams = {};
11196 this.paramNames = {
11201 "multisort" : "_multisort"
11204 if(config && config.data){
11205 this.inlineData = config.data;
11206 delete config.data;
11209 Roo.apply(this, config);
11211 if(this.reader){ // reader passed
11212 this.reader = Roo.factory(this.reader, Roo.data);
11213 this.reader.xmodule = this.xmodule || false;
11214 if(!this.recordType){
11215 this.recordType = this.reader.recordType;
11217 if(this.reader.onMetaChange){
11218 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11222 if(this.recordType){
11223 this.fields = this.recordType.prototype.fields;
11225 this.modified = [];
11229 * @event datachanged
11230 * Fires when the data cache has changed, and a widget which is using this Store
11231 * as a Record cache should refresh its view.
11232 * @param {Store} this
11234 datachanged : true,
11236 * @event metachange
11237 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11238 * @param {Store} this
11239 * @param {Object} meta The JSON metadata
11244 * Fires when Records have been added to the Store
11245 * @param {Store} this
11246 * @param {Roo.data.Record[]} records The array of Records added
11247 * @param {Number} index The index at which the record(s) were added
11252 * Fires when a Record has been removed from the Store
11253 * @param {Store} this
11254 * @param {Roo.data.Record} record The Record that was removed
11255 * @param {Number} index The index at which the record was removed
11260 * Fires when a Record has been updated
11261 * @param {Store} this
11262 * @param {Roo.data.Record} record The Record that was updated
11263 * @param {String} operation The update operation being performed. Value may be one of:
11265 Roo.data.Record.EDIT
11266 Roo.data.Record.REJECT
11267 Roo.data.Record.COMMIT
11273 * Fires when the data cache has been cleared.
11274 * @param {Store} this
11278 * @event beforeload
11279 * Fires before a request is made for a new data object. If the beforeload handler returns false
11280 * the load action will be canceled.
11281 * @param {Store} this
11282 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11286 * @event beforeloadadd
11287 * Fires after a new set of Records has been loaded.
11288 * @param {Store} this
11289 * @param {Roo.data.Record[]} records The Records that were loaded
11290 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11292 beforeloadadd : true,
11295 * Fires after a new set of Records has been loaded, before they are added to the store.
11296 * @param {Store} this
11297 * @param {Roo.data.Record[]} records The Records that were loaded
11298 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11299 * @params {Object} return from reader
11303 * @event loadexception
11304 * Fires if an exception occurs in the Proxy during loading.
11305 * Called with the signature of the Proxy's "loadexception" event.
11306 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11309 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11310 * @param {Object} load options
11311 * @param {Object} jsonData from your request (normally this contains the Exception)
11313 loadexception : true
11317 this.proxy = Roo.factory(this.proxy, Roo.data);
11318 this.proxy.xmodule = this.xmodule || false;
11319 this.relayEvents(this.proxy, ["loadexception"]);
11321 this.sortToggle = {};
11322 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11324 Roo.data.Store.superclass.constructor.call(this);
11326 if(this.inlineData){
11327 this.loadData(this.inlineData);
11328 delete this.inlineData;
11332 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11334 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11335 * without a remote query - used by combo/forms at present.
11339 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11342 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11345 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11346 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11349 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11350 * on any HTTP request
11353 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11356 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11360 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11361 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11363 remoteSort : false,
11366 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11367 * loaded or when a record is removed. (defaults to false).
11369 pruneModifiedRecords : false,
11372 lastOptions : null,
11375 * Add Records to the Store and fires the add event.
11376 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11378 add : function(records){
11379 records = [].concat(records);
11380 for(var i = 0, len = records.length; i < len; i++){
11381 records[i].join(this);
11383 var index = this.data.length;
11384 this.data.addAll(records);
11385 this.fireEvent("add", this, records, index);
11389 * Remove a Record from the Store and fires the remove event.
11390 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11392 remove : function(record){
11393 var index = this.data.indexOf(record);
11394 this.data.removeAt(index);
11396 if(this.pruneModifiedRecords){
11397 this.modified.remove(record);
11399 this.fireEvent("remove", this, record, index);
11403 * Remove all Records from the Store and fires the clear event.
11405 removeAll : function(){
11407 if(this.pruneModifiedRecords){
11408 this.modified = [];
11410 this.fireEvent("clear", this);
11414 * Inserts Records to the Store at the given index and fires the add event.
11415 * @param {Number} index The start index at which to insert the passed Records.
11416 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11418 insert : function(index, records){
11419 records = [].concat(records);
11420 for(var i = 0, len = records.length; i < len; i++){
11421 this.data.insert(index, records[i]);
11422 records[i].join(this);
11424 this.fireEvent("add", this, records, index);
11428 * Get the index within the cache of the passed Record.
11429 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11430 * @return {Number} The index of the passed Record. Returns -1 if not found.
11432 indexOf : function(record){
11433 return this.data.indexOf(record);
11437 * Get the index within the cache of the Record with the passed id.
11438 * @param {String} id The id of the Record to find.
11439 * @return {Number} The index of the Record. Returns -1 if not found.
11441 indexOfId : function(id){
11442 return this.data.indexOfKey(id);
11446 * Get the Record with the specified id.
11447 * @param {String} id The id of the Record to find.
11448 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11450 getById : function(id){
11451 return this.data.key(id);
11455 * Get the Record at the specified index.
11456 * @param {Number} index The index of the Record to find.
11457 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11459 getAt : function(index){
11460 return this.data.itemAt(index);
11464 * Returns a range of Records between specified indices.
11465 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11466 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11467 * @return {Roo.data.Record[]} An array of Records
11469 getRange : function(start, end){
11470 return this.data.getRange(start, end);
11474 storeOptions : function(o){
11475 o = Roo.apply({}, o);
11478 this.lastOptions = o;
11482 * Loads the Record cache from the configured Proxy using the configured Reader.
11484 * If using remote paging, then the first load call must specify the <em>start</em>
11485 * and <em>limit</em> properties in the options.params property to establish the initial
11486 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11488 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11489 * and this call will return before the new data has been loaded. Perform any post-processing
11490 * in a callback function, or in a "load" event handler.</strong>
11492 * @param {Object} options An object containing properties which control loading options:<ul>
11493 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11494 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11495 * passed the following arguments:<ul>
11496 * <li>r : Roo.data.Record[]</li>
11497 * <li>options: Options object from the load call</li>
11498 * <li>success: Boolean success indicator</li></ul></li>
11499 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11500 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11503 load : function(options){
11504 options = options || {};
11505 if(this.fireEvent("beforeload", this, options) !== false){
11506 this.storeOptions(options);
11507 var p = Roo.apply(options.params || {}, this.baseParams);
11508 // if meta was not loaded from remote source.. try requesting it.
11509 if (!this.reader.metaFromRemote) {
11510 p._requestMeta = 1;
11512 if(this.sortInfo && this.remoteSort){
11513 var pn = this.paramNames;
11514 p[pn["sort"]] = this.sortInfo.field;
11515 p[pn["dir"]] = this.sortInfo.direction;
11517 if (this.multiSort) {
11518 var pn = this.paramNames;
11519 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11522 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11527 * Reloads the Record cache from the configured Proxy using the configured Reader and
11528 * the options from the last load operation performed.
11529 * @param {Object} options (optional) An object containing properties which may override the options
11530 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11531 * the most recently used options are reused).
11533 reload : function(options){
11534 this.load(Roo.applyIf(options||{}, this.lastOptions));
11538 // Called as a callback by the Reader during a load operation.
11539 loadRecords : function(o, options, success){
11540 if(!o || success === false){
11541 if(success !== false){
11542 this.fireEvent("load", this, [], options, o);
11544 if(options.callback){
11545 options.callback.call(options.scope || this, [], options, false);
11549 // if data returned failure - throw an exception.
11550 if (o.success === false) {
11551 // show a message if no listener is registered.
11552 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11553 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11555 // loadmask wil be hooked into this..
11556 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11559 var r = o.records, t = o.totalRecords || r.length;
11561 this.fireEvent("beforeloadadd", this, r, options, o);
11563 if(!options || options.add !== true){
11564 if(this.pruneModifiedRecords){
11565 this.modified = [];
11567 for(var i = 0, len = r.length; i < len; i++){
11571 this.data = this.snapshot;
11572 delete this.snapshot;
11575 this.data.addAll(r);
11576 this.totalLength = t;
11578 this.fireEvent("datachanged", this);
11580 this.totalLength = Math.max(t, this.data.length+r.length);
11584 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11586 var e = new Roo.data.Record({});
11588 e.set(this.parent.displayField, this.parent.emptyTitle);
11589 e.set(this.parent.valueField, '');
11594 this.fireEvent("load", this, r, options, o);
11595 if(options.callback){
11596 options.callback.call(options.scope || this, r, options, true);
11602 * Loads data from a passed data block. A Reader which understands the format of the data
11603 * must have been configured in the constructor.
11604 * @param {Object} data The data block from which to read the Records. The format of the data expected
11605 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11606 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11608 loadData : function(o, append){
11609 var r = this.reader.readRecords(o);
11610 this.loadRecords(r, {add: append}, true);
11614 * Gets the number of cached records.
11616 * <em>If using paging, this may not be the total size of the dataset. If the data object
11617 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11618 * the data set size</em>
11620 getCount : function(){
11621 return this.data.length || 0;
11625 * Gets the total number of records in the dataset as returned by the server.
11627 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11628 * the dataset size</em>
11630 getTotalCount : function(){
11631 return this.totalLength || 0;
11635 * Returns the sort state of the Store as an object with two properties:
11637 field {String} The name of the field by which the Records are sorted
11638 direction {String} The sort order, "ASC" or "DESC"
11641 getSortState : function(){
11642 return this.sortInfo;
11646 applySort : function(){
11647 if(this.sortInfo && !this.remoteSort){
11648 var s = this.sortInfo, f = s.field;
11649 var st = this.fields.get(f).sortType;
11650 var fn = function(r1, r2){
11651 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11652 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11654 this.data.sort(s.direction, fn);
11655 if(this.snapshot && this.snapshot != this.data){
11656 this.snapshot.sort(s.direction, fn);
11662 * Sets the default sort column and order to be used by the next load operation.
11663 * @param {String} fieldName The name of the field to sort by.
11664 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11666 setDefaultSort : function(field, dir){
11667 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11671 * Sort the Records.
11672 * If remote sorting is used, the sort is performed on the server, and the cache is
11673 * reloaded. If local sorting is used, the cache is sorted internally.
11674 * @param {String} fieldName The name of the field to sort by.
11675 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11677 sort : function(fieldName, dir){
11678 var f = this.fields.get(fieldName);
11680 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11682 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11683 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11688 this.sortToggle[f.name] = dir;
11689 this.sortInfo = {field: f.name, direction: dir};
11690 if(!this.remoteSort){
11692 this.fireEvent("datachanged", this);
11694 this.load(this.lastOptions);
11699 * Calls the specified function for each of the Records in the cache.
11700 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11701 * Returning <em>false</em> aborts and exits the iteration.
11702 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11704 each : function(fn, scope){
11705 this.data.each(fn, scope);
11709 * Gets all records modified since the last commit. Modified records are persisted across load operations
11710 * (e.g., during paging).
11711 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11713 getModifiedRecords : function(){
11714 return this.modified;
11718 createFilterFn : function(property, value, anyMatch){
11719 if(!value.exec){ // not a regex
11720 value = String(value);
11721 if(value.length == 0){
11724 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11726 return function(r){
11727 return value.test(r.data[property]);
11732 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11733 * @param {String} property A field on your records
11734 * @param {Number} start The record index to start at (defaults to 0)
11735 * @param {Number} end The last record index to include (defaults to length - 1)
11736 * @return {Number} The sum
11738 sum : function(property, start, end){
11739 var rs = this.data.items, v = 0;
11740 start = start || 0;
11741 end = (end || end === 0) ? end : rs.length-1;
11743 for(var i = start; i <= end; i++){
11744 v += (rs[i].data[property] || 0);
11750 * Filter the records by a specified property.
11751 * @param {String} field A field on your records
11752 * @param {String/RegExp} value Either a string that the field
11753 * should start with or a RegExp to test against the field
11754 * @param {Boolean} anyMatch True to match any part not just the beginning
11756 filter : function(property, value, anyMatch){
11757 var fn = this.createFilterFn(property, value, anyMatch);
11758 return fn ? this.filterBy(fn) : this.clearFilter();
11762 * Filter by a function. The specified function will be called with each
11763 * record in this data source. If the function returns true the record is included,
11764 * otherwise it is filtered.
11765 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11766 * @param {Object} scope (optional) The scope of the function (defaults to this)
11768 filterBy : function(fn, scope){
11769 this.snapshot = this.snapshot || this.data;
11770 this.data = this.queryBy(fn, scope||this);
11771 this.fireEvent("datachanged", this);
11775 * Query the records by a specified property.
11776 * @param {String} field A field on your records
11777 * @param {String/RegExp} value Either a string that the field
11778 * should start with or a RegExp to test against the field
11779 * @param {Boolean} anyMatch True to match any part not just the beginning
11780 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11782 query : function(property, value, anyMatch){
11783 var fn = this.createFilterFn(property, value, anyMatch);
11784 return fn ? this.queryBy(fn) : this.data.clone();
11788 * Query by a function. The specified function will be called with each
11789 * record in this data source. If the function returns true the record is included
11791 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11792 * @param {Object} scope (optional) The scope of the function (defaults to this)
11793 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11795 queryBy : function(fn, scope){
11796 var data = this.snapshot || this.data;
11797 return data.filterBy(fn, scope||this);
11801 * Collects unique values for a particular dataIndex from this store.
11802 * @param {String} dataIndex The property to collect
11803 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11804 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11805 * @return {Array} An array of the unique values
11807 collect : function(dataIndex, allowNull, bypassFilter){
11808 var d = (bypassFilter === true && this.snapshot) ?
11809 this.snapshot.items : this.data.items;
11810 var v, sv, r = [], l = {};
11811 for(var i = 0, len = d.length; i < len; i++){
11812 v = d[i].data[dataIndex];
11814 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11823 * Revert to a view of the Record cache with no filtering applied.
11824 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11826 clearFilter : function(suppressEvent){
11827 if(this.snapshot && this.snapshot != this.data){
11828 this.data = this.snapshot;
11829 delete this.snapshot;
11830 if(suppressEvent !== true){
11831 this.fireEvent("datachanged", this);
11837 afterEdit : function(record){
11838 if(this.modified.indexOf(record) == -1){
11839 this.modified.push(record);
11841 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11845 afterReject : function(record){
11846 this.modified.remove(record);
11847 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11851 afterCommit : function(record){
11852 this.modified.remove(record);
11853 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11857 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11858 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11860 commitChanges : function(){
11861 var m = this.modified.slice(0);
11862 this.modified = [];
11863 for(var i = 0, len = m.length; i < len; i++){
11869 * Cancel outstanding changes on all changed records.
11871 rejectChanges : function(){
11872 var m = this.modified.slice(0);
11873 this.modified = [];
11874 for(var i = 0, len = m.length; i < len; i++){
11879 onMetaChange : function(meta, rtype, o){
11880 this.recordType = rtype;
11881 this.fields = rtype.prototype.fields;
11882 delete this.snapshot;
11883 this.sortInfo = meta.sortInfo || this.sortInfo;
11884 this.modified = [];
11885 this.fireEvent('metachange', this, this.reader.meta);
11888 moveIndex : function(data, type)
11890 var index = this.indexOf(data);
11892 var newIndex = index + type;
11896 this.insert(newIndex, data);
11901 * Ext JS Library 1.1.1
11902 * Copyright(c) 2006-2007, Ext JS, LLC.
11904 * Originally Released Under LGPL - original licence link has changed is not relivant.
11907 * <script type="text/javascript">
11911 * @class Roo.data.SimpleStore
11912 * @extends Roo.data.Store
11913 * Small helper class to make creating Stores from Array data easier.
11914 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11915 * @cfg {Array} fields An array of field definition objects, or field name strings.
11916 * @cfg {Array} data The multi-dimensional array of data
11918 * @param {Object} config
11920 Roo.data.SimpleStore = function(config){
11921 Roo.data.SimpleStore.superclass.constructor.call(this, {
11923 reader: new Roo.data.ArrayReader({
11926 Roo.data.Record.create(config.fields)
11928 proxy : new Roo.data.MemoryProxy(config.data)
11932 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11934 * Ext JS Library 1.1.1
11935 * Copyright(c) 2006-2007, Ext JS, LLC.
11937 * Originally Released Under LGPL - original licence link has changed is not relivant.
11940 * <script type="text/javascript">
11945 * @extends Roo.data.Store
11946 * @class Roo.data.JsonStore
11947 * Small helper class to make creating Stores for JSON data easier. <br/>
11949 var store = new Roo.data.JsonStore({
11950 url: 'get-images.php',
11952 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11955 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11956 * JsonReader and HttpProxy (unless inline data is provided).</b>
11957 * @cfg {Array} fields An array of field definition objects, or field name strings.
11959 * @param {Object} config
11961 Roo.data.JsonStore = function(c){
11962 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11963 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11964 reader: new Roo.data.JsonReader(c, c.fields)
11967 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11969 * Ext JS Library 1.1.1
11970 * Copyright(c) 2006-2007, Ext JS, LLC.
11972 * Originally Released Under LGPL - original licence link has changed is not relivant.
11975 * <script type="text/javascript">
11979 Roo.data.Field = function(config){
11980 if(typeof config == "string"){
11981 config = {name: config};
11983 Roo.apply(this, config);
11986 this.type = "auto";
11989 var st = Roo.data.SortTypes;
11990 // named sortTypes are supported, here we look them up
11991 if(typeof this.sortType == "string"){
11992 this.sortType = st[this.sortType];
11995 // set default sortType for strings and dates
11996 if(!this.sortType){
11999 this.sortType = st.asUCString;
12002 this.sortType = st.asDate;
12005 this.sortType = st.none;
12010 var stripRe = /[\$,%]/g;
12012 // prebuilt conversion function for this field, instead of
12013 // switching every time we're reading a value
12015 var cv, dateFormat = this.dateFormat;
12020 cv = function(v){ return v; };
12023 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12027 return v !== undefined && v !== null && v !== '' ?
12028 parseInt(String(v).replace(stripRe, ""), 10) : '';
12033 return v !== undefined && v !== null && v !== '' ?
12034 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12039 cv = function(v){ return v === true || v === "true" || v == 1; };
12046 if(v instanceof Date){
12050 if(dateFormat == "timestamp"){
12051 return new Date(v*1000);
12053 return Date.parseDate(v, dateFormat);
12055 var parsed = Date.parse(v);
12056 return parsed ? new Date(parsed) : null;
12065 Roo.data.Field.prototype = {
12073 * Ext JS Library 1.1.1
12074 * Copyright(c) 2006-2007, Ext JS, LLC.
12076 * Originally Released Under LGPL - original licence link has changed is not relivant.
12079 * <script type="text/javascript">
12082 // Base class for reading structured data from a data source. This class is intended to be
12083 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12086 * @class Roo.data.DataReader
12087 * Base class for reading structured data from a data source. This class is intended to be
12088 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12091 Roo.data.DataReader = function(meta, recordType){
12095 this.recordType = recordType instanceof Array ?
12096 Roo.data.Record.create(recordType) : recordType;
12099 Roo.data.DataReader.prototype = {
12101 * Create an empty record
12102 * @param {Object} data (optional) - overlay some values
12103 * @return {Roo.data.Record} record created.
12105 newRow : function(d) {
12107 this.recordType.prototype.fields.each(function(c) {
12109 case 'int' : da[c.name] = 0; break;
12110 case 'date' : da[c.name] = new Date(); break;
12111 case 'float' : da[c.name] = 0.0; break;
12112 case 'boolean' : da[c.name] = false; break;
12113 default : da[c.name] = ""; break;
12117 return new this.recordType(Roo.apply(da, d));
12122 * Ext JS Library 1.1.1
12123 * Copyright(c) 2006-2007, Ext JS, LLC.
12125 * Originally Released Under LGPL - original licence link has changed is not relivant.
12128 * <script type="text/javascript">
12132 * @class Roo.data.DataProxy
12133 * @extends Roo.data.Observable
12134 * This class is an abstract base class for implementations which provide retrieval of
12135 * unformatted data objects.<br>
12137 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12138 * (of the appropriate type which knows how to parse the data object) to provide a block of
12139 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12141 * Custom implementations must implement the load method as described in
12142 * {@link Roo.data.HttpProxy#load}.
12144 Roo.data.DataProxy = function(){
12147 * @event beforeload
12148 * Fires before a network request is made to retrieve a data object.
12149 * @param {Object} This DataProxy object.
12150 * @param {Object} params The params parameter to the load function.
12155 * Fires before the load method's callback is called.
12156 * @param {Object} This DataProxy object.
12157 * @param {Object} o The data object.
12158 * @param {Object} arg The callback argument object passed to the load function.
12162 * @event loadexception
12163 * Fires if an Exception occurs during data retrieval.
12164 * @param {Object} This DataProxy object.
12165 * @param {Object} o The data object.
12166 * @param {Object} arg The callback argument object passed to the load function.
12167 * @param {Object} e The Exception.
12169 loadexception : true
12171 Roo.data.DataProxy.superclass.constructor.call(this);
12174 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12177 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12181 * Ext JS Library 1.1.1
12182 * Copyright(c) 2006-2007, Ext JS, LLC.
12184 * Originally Released Under LGPL - original licence link has changed is not relivant.
12187 * <script type="text/javascript">
12190 * @class Roo.data.MemoryProxy
12191 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12192 * to the Reader when its load method is called.
12194 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12196 Roo.data.MemoryProxy = function(data){
12200 Roo.data.MemoryProxy.superclass.constructor.call(this);
12204 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12207 * Load data from the requested source (in this case an in-memory
12208 * data object passed to the constructor), read the data object into
12209 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12210 * process that block using the passed callback.
12211 * @param {Object} params This parameter is not used by the MemoryProxy class.
12212 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12213 * object into a block of Roo.data.Records.
12214 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12215 * The function must be passed <ul>
12216 * <li>The Record block object</li>
12217 * <li>The "arg" argument from the load function</li>
12218 * <li>A boolean success indicator</li>
12220 * @param {Object} scope The scope in which to call the callback
12221 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12223 load : function(params, reader, callback, scope, arg){
12224 params = params || {};
12227 result = reader.readRecords(this.data);
12229 this.fireEvent("loadexception", this, arg, null, e);
12230 callback.call(scope, null, arg, false);
12233 callback.call(scope, result, arg, true);
12237 update : function(params, records){
12242 * Ext JS Library 1.1.1
12243 * Copyright(c) 2006-2007, Ext JS, LLC.
12245 * Originally Released Under LGPL - original licence link has changed is not relivant.
12248 * <script type="text/javascript">
12251 * @class Roo.data.HttpProxy
12252 * @extends Roo.data.DataProxy
12253 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12254 * configured to reference a certain URL.<br><br>
12256 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12257 * from which the running page was served.<br><br>
12259 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12261 * Be aware that to enable the browser to parse an XML document, the server must set
12262 * the Content-Type header in the HTTP response to "text/xml".
12264 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12265 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12266 * will be used to make the request.
12268 Roo.data.HttpProxy = function(conn){
12269 Roo.data.HttpProxy.superclass.constructor.call(this);
12270 // is conn a conn config or a real conn?
12272 this.useAjax = !conn || !conn.events;
12276 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12277 // thse are take from connection...
12280 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12283 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12284 * extra parameters to each request made by this object. (defaults to undefined)
12287 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12288 * to each request made by this object. (defaults to undefined)
12291 * @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)
12294 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12297 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12303 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12307 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12308 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12309 * a finer-grained basis than the DataProxy events.
12311 getConnection : function(){
12312 return this.useAjax ? Roo.Ajax : this.conn;
12316 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12317 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12318 * process that block using the passed callback.
12319 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12320 * for the request to the remote server.
12321 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12322 * object into a block of Roo.data.Records.
12323 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12324 * The function must be passed <ul>
12325 * <li>The Record block object</li>
12326 * <li>The "arg" argument from the load function</li>
12327 * <li>A boolean success indicator</li>
12329 * @param {Object} scope The scope in which to call the callback
12330 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12332 load : function(params, reader, callback, scope, arg){
12333 if(this.fireEvent("beforeload", this, params) !== false){
12335 params : params || {},
12337 callback : callback,
12342 callback : this.loadResponse,
12346 Roo.applyIf(o, this.conn);
12347 if(this.activeRequest){
12348 Roo.Ajax.abort(this.activeRequest);
12350 this.activeRequest = Roo.Ajax.request(o);
12352 this.conn.request(o);
12355 callback.call(scope||this, null, arg, false);
12360 loadResponse : function(o, success, response){
12361 delete this.activeRequest;
12363 this.fireEvent("loadexception", this, o, response);
12364 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12369 result = o.reader.read(response);
12371 this.fireEvent("loadexception", this, o, response, e);
12372 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12376 this.fireEvent("load", this, o, o.request.arg);
12377 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12381 update : function(dataSet){
12386 updateResponse : function(dataSet){
12391 * Ext JS Library 1.1.1
12392 * Copyright(c) 2006-2007, Ext JS, LLC.
12394 * Originally Released Under LGPL - original licence link has changed is not relivant.
12397 * <script type="text/javascript">
12401 * @class Roo.data.ScriptTagProxy
12402 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12403 * other than the originating domain of the running page.<br><br>
12405 * <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
12406 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12408 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12409 * source code that is used as the source inside a <script> tag.<br><br>
12411 * In order for the browser to process the returned data, the server must wrap the data object
12412 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12413 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12414 * depending on whether the callback name was passed:
12417 boolean scriptTag = false;
12418 String cb = request.getParameter("callback");
12421 response.setContentType("text/javascript");
12423 response.setContentType("application/x-json");
12425 Writer out = response.getWriter();
12427 out.write(cb + "(");
12429 out.print(dataBlock.toJsonString());
12436 * @param {Object} config A configuration object.
12438 Roo.data.ScriptTagProxy = function(config){
12439 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12440 Roo.apply(this, config);
12441 this.head = document.getElementsByTagName("head")[0];
12444 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12446 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12448 * @cfg {String} url The URL from which to request the data object.
12451 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12455 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12456 * the server the name of the callback function set up by the load call to process the returned data object.
12457 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12458 * javascript output which calls this named function passing the data object as its only parameter.
12460 callbackParam : "callback",
12462 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12463 * name to the request.
12468 * Load data from the configured URL, read the data object into
12469 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12470 * process that block using the passed callback.
12471 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12472 * for the request to the remote server.
12473 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12474 * object into a block of Roo.data.Records.
12475 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12476 * The function must be passed <ul>
12477 * <li>The Record block object</li>
12478 * <li>The "arg" argument from the load function</li>
12479 * <li>A boolean success indicator</li>
12481 * @param {Object} scope The scope in which to call the callback
12482 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12484 load : function(params, reader, callback, scope, arg){
12485 if(this.fireEvent("beforeload", this, params) !== false){
12487 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12489 var url = this.url;
12490 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12492 url += "&_dc=" + (new Date().getTime());
12494 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12497 cb : "stcCallback"+transId,
12498 scriptId : "stcScript"+transId,
12502 callback : callback,
12508 window[trans.cb] = function(o){
12509 conn.handleResponse(o, trans);
12512 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12514 if(this.autoAbort !== false){
12518 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12520 var script = document.createElement("script");
12521 script.setAttribute("src", url);
12522 script.setAttribute("type", "text/javascript");
12523 script.setAttribute("id", trans.scriptId);
12524 this.head.appendChild(script);
12526 this.trans = trans;
12528 callback.call(scope||this, null, arg, false);
12533 isLoading : function(){
12534 return this.trans ? true : false;
12538 * Abort the current server request.
12540 abort : function(){
12541 if(this.isLoading()){
12542 this.destroyTrans(this.trans);
12547 destroyTrans : function(trans, isLoaded){
12548 this.head.removeChild(document.getElementById(trans.scriptId));
12549 clearTimeout(trans.timeoutId);
12551 window[trans.cb] = undefined;
12553 delete window[trans.cb];
12556 // if hasn't been loaded, wait for load to remove it to prevent script error
12557 window[trans.cb] = function(){
12558 window[trans.cb] = undefined;
12560 delete window[trans.cb];
12567 handleResponse : function(o, trans){
12568 this.trans = false;
12569 this.destroyTrans(trans, true);
12572 result = trans.reader.readRecords(o);
12574 this.fireEvent("loadexception", this, o, trans.arg, e);
12575 trans.callback.call(trans.scope||window, null, trans.arg, false);
12578 this.fireEvent("load", this, o, trans.arg);
12579 trans.callback.call(trans.scope||window, result, trans.arg, true);
12583 handleFailure : function(trans){
12584 this.trans = false;
12585 this.destroyTrans(trans, false);
12586 this.fireEvent("loadexception", this, null, trans.arg);
12587 trans.callback.call(trans.scope||window, null, trans.arg, false);
12591 * Ext JS Library 1.1.1
12592 * Copyright(c) 2006-2007, Ext JS, LLC.
12594 * Originally Released Under LGPL - original licence link has changed is not relivant.
12597 * <script type="text/javascript">
12601 * @class Roo.data.JsonReader
12602 * @extends Roo.data.DataReader
12603 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12604 * based on mappings in a provided Roo.data.Record constructor.
12606 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12607 * in the reply previously.
12612 var RecordDef = Roo.data.Record.create([
12613 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12614 {name: 'occupation'} // This field will use "occupation" as the mapping.
12616 var myReader = new Roo.data.JsonReader({
12617 totalProperty: "results", // The property which contains the total dataset size (optional)
12618 root: "rows", // The property which contains an Array of row objects
12619 id: "id" // The property within each row object that provides an ID for the record (optional)
12623 * This would consume a JSON file like this:
12625 { 'results': 2, 'rows': [
12626 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12627 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12630 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12631 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12632 * paged from the remote server.
12633 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12634 * @cfg {String} root name of the property which contains the Array of row objects.
12635 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12636 * @cfg {Array} fields Array of field definition objects
12638 * Create a new JsonReader
12639 * @param {Object} meta Metadata configuration options
12640 * @param {Object} recordType Either an Array of field definition objects,
12641 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12643 Roo.data.JsonReader = function(meta, recordType){
12646 // set some defaults:
12647 Roo.applyIf(meta, {
12648 totalProperty: 'total',
12649 successProperty : 'success',
12654 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12656 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12659 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12660 * Used by Store query builder to append _requestMeta to params.
12663 metaFromRemote : false,
12665 * This method is only used by a DataProxy which has retrieved data from a remote server.
12666 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12667 * @return {Object} data A data block which is used by an Roo.data.Store object as
12668 * a cache of Roo.data.Records.
12670 read : function(response){
12671 var json = response.responseText;
12673 var o = /* eval:var:o */ eval("("+json+")");
12675 throw {message: "JsonReader.read: Json object not found"};
12681 this.metaFromRemote = true;
12682 this.meta = o.metaData;
12683 this.recordType = Roo.data.Record.create(o.metaData.fields);
12684 this.onMetaChange(this.meta, this.recordType, o);
12686 return this.readRecords(o);
12689 // private function a store will implement
12690 onMetaChange : function(meta, recordType, o){
12697 simpleAccess: function(obj, subsc) {
12704 getJsonAccessor: function(){
12706 return function(expr) {
12708 return(re.test(expr))
12709 ? new Function("obj", "return obj." + expr)
12714 return Roo.emptyFn;
12719 * Create a data block containing Roo.data.Records from an XML document.
12720 * @param {Object} o An object which contains an Array of row objects in the property specified
12721 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12722 * which contains the total size of the dataset.
12723 * @return {Object} data A data block which is used by an Roo.data.Store object as
12724 * a cache of Roo.data.Records.
12726 readRecords : function(o){
12728 * After any data loads, the raw JSON data is available for further custom processing.
12732 var s = this.meta, Record = this.recordType,
12733 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12735 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12737 if(s.totalProperty) {
12738 this.getTotal = this.getJsonAccessor(s.totalProperty);
12740 if(s.successProperty) {
12741 this.getSuccess = this.getJsonAccessor(s.successProperty);
12743 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12745 var g = this.getJsonAccessor(s.id);
12746 this.getId = function(rec) {
12748 return (r === undefined || r === "") ? null : r;
12751 this.getId = function(){return null;};
12754 for(var jj = 0; jj < fl; jj++){
12756 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12757 this.ef[jj] = this.getJsonAccessor(map);
12761 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12762 if(s.totalProperty){
12763 var vt = parseInt(this.getTotal(o), 10);
12768 if(s.successProperty){
12769 var vs = this.getSuccess(o);
12770 if(vs === false || vs === 'false'){
12775 for(var i = 0; i < c; i++){
12778 var id = this.getId(n);
12779 for(var j = 0; j < fl; j++){
12781 var v = this.ef[j](n);
12783 Roo.log('missing convert for ' + f.name);
12787 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12789 var record = new Record(values, id);
12791 records[i] = record;
12797 totalRecords : totalRecords
12802 * Ext JS Library 1.1.1
12803 * Copyright(c) 2006-2007, Ext JS, LLC.
12805 * Originally Released Under LGPL - original licence link has changed is not relivant.
12808 * <script type="text/javascript">
12812 * @class Roo.data.ArrayReader
12813 * @extends Roo.data.DataReader
12814 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12815 * Each element of that Array represents a row of data fields. The
12816 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12817 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12821 var RecordDef = Roo.data.Record.create([
12822 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12823 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12825 var myReader = new Roo.data.ArrayReader({
12826 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12830 * This would consume an Array like this:
12832 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12834 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12836 * Create a new JsonReader
12837 * @param {Object} meta Metadata configuration options.
12838 * @param {Object} recordType Either an Array of field definition objects
12839 * as specified to {@link Roo.data.Record#create},
12840 * or an {@link Roo.data.Record} object
12841 * created using {@link Roo.data.Record#create}.
12843 Roo.data.ArrayReader = function(meta, recordType){
12844 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12847 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12849 * Create a data block containing Roo.data.Records from an XML document.
12850 * @param {Object} o An Array of row objects which represents the dataset.
12851 * @return {Object} data A data block which is used by an Roo.data.Store object as
12852 * a cache of Roo.data.Records.
12854 readRecords : function(o){
12855 var sid = this.meta ? this.meta.id : null;
12856 var recordType = this.recordType, fields = recordType.prototype.fields;
12859 for(var i = 0; i < root.length; i++){
12862 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12863 for(var j = 0, jlen = fields.length; j < jlen; j++){
12864 var f = fields.items[j];
12865 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12866 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12868 values[f.name] = v;
12870 var record = new recordType(values, id);
12872 records[records.length] = record;
12876 totalRecords : records.length
12885 * @class Roo.bootstrap.ComboBox
12886 * @extends Roo.bootstrap.TriggerField
12887 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12888 * @cfg {Boolean} append (true|false) default false
12889 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12890 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12891 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12892 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12893 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12894 * @cfg {Boolean} animate default true
12895 * @cfg {Boolean} emptyResultText only for touch device
12896 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12897 * @cfg {String} emptyTitle default ''
12899 * Create a new ComboBox.
12900 * @param {Object} config Configuration options
12902 Roo.bootstrap.ComboBox = function(config){
12903 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12907 * Fires when the dropdown list is expanded
12908 * @param {Roo.bootstrap.ComboBox} combo This combo box
12913 * Fires when the dropdown list is collapsed
12914 * @param {Roo.bootstrap.ComboBox} combo This combo box
12918 * @event beforeselect
12919 * Fires before a list item is selected. Return false to cancel the selection.
12920 * @param {Roo.bootstrap.ComboBox} combo This combo box
12921 * @param {Roo.data.Record} record The data record returned from the underlying store
12922 * @param {Number} index The index of the selected item in the dropdown list
12924 'beforeselect' : true,
12927 * Fires when a list item is selected
12928 * @param {Roo.bootstrap.ComboBox} combo This combo box
12929 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12930 * @param {Number} index The index of the selected item in the dropdown list
12934 * @event beforequery
12935 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12936 * The event object passed has these properties:
12937 * @param {Roo.bootstrap.ComboBox} combo This combo box
12938 * @param {String} query The query
12939 * @param {Boolean} forceAll true to force "all" query
12940 * @param {Boolean} cancel true to cancel the query
12941 * @param {Object} e The query event object
12943 'beforequery': true,
12946 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12947 * @param {Roo.bootstrap.ComboBox} combo This combo box
12952 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12953 * @param {Roo.bootstrap.ComboBox} combo This combo box
12954 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12959 * Fires when the remove value from the combobox array
12960 * @param {Roo.bootstrap.ComboBox} combo This combo box
12964 * @event afterremove
12965 * Fires when the remove value from the combobox array
12966 * @param {Roo.bootstrap.ComboBox} combo This combo box
12968 'afterremove' : true,
12970 * @event specialfilter
12971 * Fires when specialfilter
12972 * @param {Roo.bootstrap.ComboBox} combo This combo box
12974 'specialfilter' : true,
12977 * Fires when tick the element
12978 * @param {Roo.bootstrap.ComboBox} combo This combo box
12982 * @event touchviewdisplay
12983 * Fires when touch view require special display (default is using displayField)
12984 * @param {Roo.bootstrap.ComboBox} combo This combo box
12985 * @param {Object} cfg set html .
12987 'touchviewdisplay' : true
12992 this.tickItems = [];
12994 this.selectedIndex = -1;
12995 if(this.mode == 'local'){
12996 if(config.queryDelay === undefined){
12997 this.queryDelay = 10;
12999 if(config.minChars === undefined){
13005 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13008 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13009 * rendering into an Roo.Editor, defaults to false)
13012 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13013 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13016 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13019 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13020 * the dropdown list (defaults to undefined, with no header element)
13024 * @cfg {String/Roo.Template} tpl The template to use to render the output
13028 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13030 listWidth: undefined,
13032 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13033 * mode = 'remote' or 'text' if mode = 'local')
13035 displayField: undefined,
13038 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13039 * mode = 'remote' or 'value' if mode = 'local').
13040 * Note: use of a valueField requires the user make a selection
13041 * in order for a value to be mapped.
13043 valueField: undefined,
13045 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13050 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13051 * field's data value (defaults to the underlying DOM element's name)
13053 hiddenName: undefined,
13055 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13059 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13061 selectedClass: 'active',
13064 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13068 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13069 * anchor positions (defaults to 'tl-bl')
13071 listAlign: 'tl-bl?',
13073 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13077 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13078 * query specified by the allQuery config option (defaults to 'query')
13080 triggerAction: 'query',
13082 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13083 * (defaults to 4, does not apply if editable = false)
13087 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13088 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13092 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13093 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13097 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13098 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13102 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13103 * when editable = true (defaults to false)
13105 selectOnFocus:false,
13107 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13109 queryParam: 'query',
13111 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13112 * when mode = 'remote' (defaults to 'Loading...')
13114 loadingText: 'Loading...',
13116 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13120 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13124 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13125 * traditional select (defaults to true)
13129 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13133 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13137 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13138 * listWidth has a higher value)
13142 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13143 * allow the user to set arbitrary text into the field (defaults to false)
13145 forceSelection:false,
13147 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13148 * if typeAhead = true (defaults to 250)
13150 typeAheadDelay : 250,
13152 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13153 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13155 valueNotFoundText : undefined,
13157 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13159 blockFocus : false,
13162 * @cfg {Boolean} disableClear Disable showing of clear button.
13164 disableClear : false,
13166 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13168 alwaysQuery : false,
13171 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13176 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13178 invalidClass : "has-warning",
13181 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13183 validClass : "has-success",
13186 * @cfg {Boolean} specialFilter (true|false) special filter default false
13188 specialFilter : false,
13191 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13193 mobileTouchView : true,
13196 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13198 useNativeIOS : false,
13201 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13203 mobile_restrict_height : false,
13205 ios_options : false,
13217 btnPosition : 'right',
13218 triggerList : true,
13219 showToggleBtn : true,
13221 emptyResultText: 'Empty',
13222 triggerText : 'Select',
13225 // element that contains real text value.. (when hidden is used..)
13227 getAutoCreate : function()
13232 * Render classic select for iso
13235 if(Roo.isIOS && this.useNativeIOS){
13236 cfg = this.getAutoCreateNativeIOS();
13244 if(Roo.isTouch && this.mobileTouchView){
13245 cfg = this.getAutoCreateTouchView();
13252 if(!this.tickable){
13253 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13258 * ComboBox with tickable selections
13261 var align = this.labelAlign || this.parentLabelAlign();
13264 cls : 'form-group roo-combobox-tickable' //input-group
13267 var btn_text_select = '';
13268 var btn_text_done = '';
13269 var btn_text_cancel = '';
13271 if (this.btn_text_show) {
13272 btn_text_select = 'Select';
13273 btn_text_done = 'Done';
13274 btn_text_cancel = 'Cancel';
13279 cls : 'tickable-buttons',
13284 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13285 //html : this.triggerText
13286 html: btn_text_select
13292 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13294 html: btn_text_done
13300 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13302 html: btn_text_cancel
13308 buttons.cn.unshift({
13310 cls: 'roo-select2-search-field-input'
13316 Roo.each(buttons.cn, function(c){
13318 c.cls += ' btn-' + _this.size;
13321 if (_this.disabled) {
13332 cls: 'form-hidden-field'
13336 cls: 'roo-select2-choices',
13340 cls: 'roo-select2-search-field',
13351 cls: 'roo-select2-container input-group roo-select2-container-multi',
13356 // cls: 'typeahead typeahead-long dropdown-menu',
13357 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13362 if(this.hasFeedback && !this.allowBlank){
13366 cls: 'glyphicon form-control-feedback'
13369 combobox.cn.push(feedback);
13373 if (align ==='left' && this.fieldLabel.length) {
13375 cfg.cls += ' roo-form-group-label-left';
13380 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13381 tooltip : 'This field is required'
13386 cls : 'control-label',
13387 html : this.fieldLabel
13399 var labelCfg = cfg.cn[1];
13400 var contentCfg = cfg.cn[2];
13403 if(this.indicatorpos == 'right'){
13409 cls : 'control-label',
13413 html : this.fieldLabel
13417 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13418 tooltip : 'This field is required'
13433 labelCfg = cfg.cn[0];
13434 contentCfg = cfg.cn[1];
13438 if(this.labelWidth > 12){
13439 labelCfg.style = "width: " + this.labelWidth + 'px';
13442 if(this.labelWidth < 13 && this.labelmd == 0){
13443 this.labelmd = this.labelWidth;
13446 if(this.labellg > 0){
13447 labelCfg.cls += ' col-lg-' + this.labellg;
13448 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13451 if(this.labelmd > 0){
13452 labelCfg.cls += ' col-md-' + this.labelmd;
13453 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13456 if(this.labelsm > 0){
13457 labelCfg.cls += ' col-sm-' + this.labelsm;
13458 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13461 if(this.labelxs > 0){
13462 labelCfg.cls += ' col-xs-' + this.labelxs;
13463 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13467 } else if ( this.fieldLabel.length) {
13468 // Roo.log(" label");
13472 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13473 tooltip : 'This field is required'
13477 //cls : 'input-group-addon',
13478 html : this.fieldLabel
13483 if(this.indicatorpos == 'right'){
13487 //cls : 'input-group-addon',
13488 html : this.fieldLabel
13492 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13493 tooltip : 'This field is required'
13502 // Roo.log(" no label && no align");
13509 ['xs','sm','md','lg'].map(function(size){
13510 if (settings[size]) {
13511 cfg.cls += ' col-' + size + '-' + settings[size];
13519 _initEventsCalled : false,
13522 initEvents: function()
13524 if (this._initEventsCalled) { // as we call render... prevent looping...
13527 this._initEventsCalled = true;
13530 throw "can not find store for combo";
13533 this.indicator = this.indicatorEl();
13535 this.store = Roo.factory(this.store, Roo.data);
13536 this.store.parent = this;
13538 // if we are building from html. then this element is so complex, that we can not really
13539 // use the rendered HTML.
13540 // so we have to trash and replace the previous code.
13541 if (Roo.XComponent.build_from_html) {
13542 // remove this element....
13543 var e = this.el.dom, k=0;
13544 while (e ) { e = e.previousSibling; ++k;}
13549 this.rendered = false;
13551 this.render(this.parent().getChildContainer(true), k);
13554 if(Roo.isIOS && this.useNativeIOS){
13555 this.initIOSView();
13563 if(Roo.isTouch && this.mobileTouchView){
13564 this.initTouchView();
13569 this.initTickableEvents();
13573 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13575 if(this.hiddenName){
13577 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13579 this.hiddenField.dom.value =
13580 this.hiddenValue !== undefined ? this.hiddenValue :
13581 this.value !== undefined ? this.value : '';
13583 // prevent input submission
13584 this.el.dom.removeAttribute('name');
13585 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13590 // this.el.dom.setAttribute('autocomplete', 'off');
13593 var cls = 'x-combo-list';
13595 //this.list = new Roo.Layer({
13596 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13602 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13603 _this.list.setWidth(lw);
13606 this.list.on('mouseover', this.onViewOver, this);
13607 this.list.on('mousemove', this.onViewMove, this);
13608 this.list.on('scroll', this.onViewScroll, this);
13611 this.list.swallowEvent('mousewheel');
13612 this.assetHeight = 0;
13615 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13616 this.assetHeight += this.header.getHeight();
13619 this.innerList = this.list.createChild({cls:cls+'-inner'});
13620 this.innerList.on('mouseover', this.onViewOver, this);
13621 this.innerList.on('mousemove', this.onViewMove, this);
13622 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13624 if(this.allowBlank && !this.pageSize && !this.disableClear){
13625 this.footer = this.list.createChild({cls:cls+'-ft'});
13626 this.pageTb = new Roo.Toolbar(this.footer);
13630 this.footer = this.list.createChild({cls:cls+'-ft'});
13631 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13632 {pageSize: this.pageSize});
13636 if (this.pageTb && this.allowBlank && !this.disableClear) {
13638 this.pageTb.add(new Roo.Toolbar.Fill(), {
13639 cls: 'x-btn-icon x-btn-clear',
13641 handler: function()
13644 _this.clearValue();
13645 _this.onSelect(false, -1);
13650 this.assetHeight += this.footer.getHeight();
13655 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13658 this.view = new Roo.View(this.list, this.tpl, {
13659 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13661 //this.view.wrapEl.setDisplayed(false);
13662 this.view.on('click', this.onViewClick, this);
13665 this.store.on('beforeload', this.onBeforeLoad, this);
13666 this.store.on('load', this.onLoad, this);
13667 this.store.on('loadexception', this.onLoadException, this);
13669 if(this.resizable){
13670 this.resizer = new Roo.Resizable(this.list, {
13671 pinned:true, handles:'se'
13673 this.resizer.on('resize', function(r, w, h){
13674 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13675 this.listWidth = w;
13676 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13677 this.restrictHeight();
13679 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13682 if(!this.editable){
13683 this.editable = true;
13684 this.setEditable(false);
13689 if (typeof(this.events.add.listeners) != 'undefined') {
13691 this.addicon = this.wrap.createChild(
13692 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13694 this.addicon.on('click', function(e) {
13695 this.fireEvent('add', this);
13698 if (typeof(this.events.edit.listeners) != 'undefined') {
13700 this.editicon = this.wrap.createChild(
13701 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13702 if (this.addicon) {
13703 this.editicon.setStyle('margin-left', '40px');
13705 this.editicon.on('click', function(e) {
13707 // we fire even if inothing is selected..
13708 this.fireEvent('edit', this, this.lastData );
13714 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13715 "up" : function(e){
13716 this.inKeyMode = true;
13720 "down" : function(e){
13721 if(!this.isExpanded()){
13722 this.onTriggerClick();
13724 this.inKeyMode = true;
13729 "enter" : function(e){
13730 // this.onViewClick();
13734 if(this.fireEvent("specialkey", this, e)){
13735 this.onViewClick(false);
13741 "esc" : function(e){
13745 "tab" : function(e){
13748 if(this.fireEvent("specialkey", this, e)){
13749 this.onViewClick(false);
13757 doRelay : function(foo, bar, hname){
13758 if(hname == 'down' || this.scope.isExpanded()){
13759 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13768 this.queryDelay = Math.max(this.queryDelay || 10,
13769 this.mode == 'local' ? 10 : 250);
13772 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13774 if(this.typeAhead){
13775 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13777 if(this.editable !== false){
13778 this.inputEl().on("keyup", this.onKeyUp, this);
13780 if(this.forceSelection){
13781 this.inputEl().on('blur', this.doForce, this);
13785 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13786 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13790 initTickableEvents: function()
13794 if(this.hiddenName){
13796 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13798 this.hiddenField.dom.value =
13799 this.hiddenValue !== undefined ? this.hiddenValue :
13800 this.value !== undefined ? this.value : '';
13802 // prevent input submission
13803 this.el.dom.removeAttribute('name');
13804 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13809 // this.list = this.el.select('ul.dropdown-menu',true).first();
13811 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13812 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13813 if(this.triggerList){
13814 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13817 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13818 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13820 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13821 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13823 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13824 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13826 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13827 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13828 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13831 this.cancelBtn.hide();
13836 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13837 _this.list.setWidth(lw);
13840 this.list.on('mouseover', this.onViewOver, this);
13841 this.list.on('mousemove', this.onViewMove, this);
13843 this.list.on('scroll', this.onViewScroll, this);
13846 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13847 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13850 this.view = new Roo.View(this.list, this.tpl, {
13855 selectedClass: this.selectedClass
13858 //this.view.wrapEl.setDisplayed(false);
13859 this.view.on('click', this.onViewClick, this);
13863 this.store.on('beforeload', this.onBeforeLoad, this);
13864 this.store.on('load', this.onLoad, this);
13865 this.store.on('loadexception', this.onLoadException, this);
13868 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13869 "up" : function(e){
13870 this.inKeyMode = true;
13874 "down" : function(e){
13875 this.inKeyMode = true;
13879 "enter" : function(e){
13880 if(this.fireEvent("specialkey", this, e)){
13881 this.onViewClick(false);
13887 "esc" : function(e){
13888 this.onTickableFooterButtonClick(e, false, false);
13891 "tab" : function(e){
13892 this.fireEvent("specialkey", this, e);
13894 this.onTickableFooterButtonClick(e, false, false);
13901 doRelay : function(e, fn, key){
13902 if(this.scope.isExpanded()){
13903 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13912 this.queryDelay = Math.max(this.queryDelay || 10,
13913 this.mode == 'local' ? 10 : 250);
13916 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13918 if(this.typeAhead){
13919 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13922 if(this.editable !== false){
13923 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13926 this.indicator = this.indicatorEl();
13928 if(this.indicator){
13929 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13930 this.indicator.hide();
13935 onDestroy : function(){
13937 this.view.setStore(null);
13938 this.view.el.removeAllListeners();
13939 this.view.el.remove();
13940 this.view.purgeListeners();
13943 this.list.dom.innerHTML = '';
13947 this.store.un('beforeload', this.onBeforeLoad, this);
13948 this.store.un('load', this.onLoad, this);
13949 this.store.un('loadexception', this.onLoadException, this);
13951 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13955 fireKey : function(e){
13956 if(e.isNavKeyPress() && !this.list.isVisible()){
13957 this.fireEvent("specialkey", this, e);
13962 onResize: function(w, h){
13963 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13965 // if(typeof w != 'number'){
13966 // // we do not handle it!?!?
13969 // var tw = this.trigger.getWidth();
13970 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13971 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13973 // this.inputEl().setWidth( this.adjustWidth('input', x));
13975 // //this.trigger.setStyle('left', x+'px');
13977 // if(this.list && this.listWidth === undefined){
13978 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13979 // this.list.setWidth(lw);
13980 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13988 * Allow or prevent the user from directly editing the field text. If false is passed,
13989 * the user will only be able to select from the items defined in the dropdown list. This method
13990 * is the runtime equivalent of setting the 'editable' config option at config time.
13991 * @param {Boolean} value True to allow the user to directly edit the field text
13993 setEditable : function(value){
13994 if(value == this.editable){
13997 this.editable = value;
13999 this.inputEl().dom.setAttribute('readOnly', true);
14000 this.inputEl().on('mousedown', this.onTriggerClick, this);
14001 this.inputEl().addClass('x-combo-noedit');
14003 this.inputEl().dom.setAttribute('readOnly', false);
14004 this.inputEl().un('mousedown', this.onTriggerClick, this);
14005 this.inputEl().removeClass('x-combo-noedit');
14011 onBeforeLoad : function(combo,opts){
14012 if(!this.hasFocus){
14016 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14018 this.restrictHeight();
14019 this.selectedIndex = -1;
14023 onLoad : function(){
14025 this.hasQuery = false;
14027 if(!this.hasFocus){
14031 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14032 this.loading.hide();
14035 if(this.store.getCount() > 0){
14038 this.restrictHeight();
14039 if(this.lastQuery == this.allQuery){
14040 if(this.editable && !this.tickable){
14041 this.inputEl().dom.select();
14045 !this.selectByValue(this.value, true) &&
14048 !this.store.lastOptions ||
14049 typeof(this.store.lastOptions.add) == 'undefined' ||
14050 this.store.lastOptions.add != true
14053 this.select(0, true);
14056 if(this.autoFocus){
14059 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14060 this.taTask.delay(this.typeAheadDelay);
14064 this.onEmptyResults();
14070 onLoadException : function()
14072 this.hasQuery = false;
14074 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14075 this.loading.hide();
14078 if(this.tickable && this.editable){
14083 // only causes errors at present
14084 //Roo.log(this.store.reader.jsonData);
14085 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14087 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14093 onTypeAhead : function(){
14094 if(this.store.getCount() > 0){
14095 var r = this.store.getAt(0);
14096 var newValue = r.data[this.displayField];
14097 var len = newValue.length;
14098 var selStart = this.getRawValue().length;
14100 if(selStart != len){
14101 this.setRawValue(newValue);
14102 this.selectText(selStart, newValue.length);
14108 onSelect : function(record, index){
14110 if(this.fireEvent('beforeselect', this, record, index) !== false){
14112 this.setFromData(index > -1 ? record.data : false);
14115 this.fireEvent('select', this, record, index);
14120 * Returns the currently selected field value or empty string if no value is set.
14121 * @return {String} value The selected value
14123 getValue : function()
14125 if(Roo.isIOS && this.useNativeIOS){
14126 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14130 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14133 if(this.valueField){
14134 return typeof this.value != 'undefined' ? this.value : '';
14136 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14140 getRawValue : function()
14142 if(Roo.isIOS && this.useNativeIOS){
14143 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14146 var v = this.inputEl().getValue();
14152 * Clears any text/value currently set in the field
14154 clearValue : function(){
14156 if(this.hiddenField){
14157 this.hiddenField.dom.value = '';
14160 this.setRawValue('');
14161 this.lastSelectionText = '';
14162 this.lastData = false;
14164 var close = this.closeTriggerEl();
14175 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14176 * will be displayed in the field. If the value does not match the data value of an existing item,
14177 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14178 * Otherwise the field will be blank (although the value will still be set).
14179 * @param {String} value The value to match
14181 setValue : function(v)
14183 if(Roo.isIOS && this.useNativeIOS){
14184 this.setIOSValue(v);
14194 if(this.valueField){
14195 var r = this.findRecord(this.valueField, v);
14197 text = r.data[this.displayField];
14198 }else if(this.valueNotFoundText !== undefined){
14199 text = this.valueNotFoundText;
14202 this.lastSelectionText = text;
14203 if(this.hiddenField){
14204 this.hiddenField.dom.value = v;
14206 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14209 var close = this.closeTriggerEl();
14212 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14218 * @property {Object} the last set data for the element
14223 * Sets the value of the field based on a object which is related to the record format for the store.
14224 * @param {Object} value the value to set as. or false on reset?
14226 setFromData : function(o){
14233 var dv = ''; // display value
14234 var vv = ''; // value value..
14236 if (this.displayField) {
14237 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14239 // this is an error condition!!!
14240 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14243 if(this.valueField){
14244 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14247 var close = this.closeTriggerEl();
14250 if(dv.length || vv * 1 > 0){
14252 this.blockFocus=true;
14258 if(this.hiddenField){
14259 this.hiddenField.dom.value = vv;
14261 this.lastSelectionText = dv;
14262 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14266 // no hidden field.. - we store the value in 'value', but still display
14267 // display field!!!!
14268 this.lastSelectionText = dv;
14269 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14276 reset : function(){
14277 // overridden so that last data is reset..
14284 this.setValue(this.originalValue);
14285 //this.clearInvalid();
14286 this.lastData = false;
14288 this.view.clearSelections();
14294 findRecord : function(prop, value){
14296 if(this.store.getCount() > 0){
14297 this.store.each(function(r){
14298 if(r.data[prop] == value){
14308 getName: function()
14310 // returns hidden if it's set..
14311 if (!this.rendered) {return ''};
14312 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14316 onViewMove : function(e, t){
14317 this.inKeyMode = false;
14321 onViewOver : function(e, t){
14322 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14325 var item = this.view.findItemFromChild(t);
14328 var index = this.view.indexOf(item);
14329 this.select(index, false);
14334 onViewClick : function(view, doFocus, el, e)
14336 var index = this.view.getSelectedIndexes()[0];
14338 var r = this.store.getAt(index);
14342 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14349 Roo.each(this.tickItems, function(v,k){
14351 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14353 _this.tickItems.splice(k, 1);
14355 if(typeof(e) == 'undefined' && view == false){
14356 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14368 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14369 this.tickItems.push(r.data);
14372 if(typeof(e) == 'undefined' && view == false){
14373 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14380 this.onSelect(r, index);
14382 if(doFocus !== false && !this.blockFocus){
14383 this.inputEl().focus();
14388 restrictHeight : function(){
14389 //this.innerList.dom.style.height = '';
14390 //var inner = this.innerList.dom;
14391 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14392 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14393 //this.list.beginUpdate();
14394 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14395 this.list.alignTo(this.inputEl(), this.listAlign);
14396 this.list.alignTo(this.inputEl(), this.listAlign);
14397 //this.list.endUpdate();
14401 onEmptyResults : function(){
14403 if(this.tickable && this.editable){
14404 this.hasFocus = false;
14405 this.restrictHeight();
14413 * Returns true if the dropdown list is expanded, else false.
14415 isExpanded : function(){
14416 return this.list.isVisible();
14420 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14421 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14422 * @param {String} value The data value of the item to select
14423 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14424 * selected item if it is not currently in view (defaults to true)
14425 * @return {Boolean} True if the value matched an item in the list, else false
14427 selectByValue : function(v, scrollIntoView){
14428 if(v !== undefined && v !== null){
14429 var r = this.findRecord(this.valueField || this.displayField, v);
14431 this.select(this.store.indexOf(r), scrollIntoView);
14439 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14440 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14441 * @param {Number} index The zero-based index of the list item to select
14442 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14443 * selected item if it is not currently in view (defaults to true)
14445 select : function(index, scrollIntoView){
14446 this.selectedIndex = index;
14447 this.view.select(index);
14448 if(scrollIntoView !== false){
14449 var el = this.view.getNode(index);
14451 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14454 this.list.scrollChildIntoView(el, false);
14460 selectNext : function(){
14461 var ct = this.store.getCount();
14463 if(this.selectedIndex == -1){
14465 }else if(this.selectedIndex < ct-1){
14466 this.select(this.selectedIndex+1);
14472 selectPrev : function(){
14473 var ct = this.store.getCount();
14475 if(this.selectedIndex == -1){
14477 }else if(this.selectedIndex != 0){
14478 this.select(this.selectedIndex-1);
14484 onKeyUp : function(e){
14485 if(this.editable !== false && !e.isSpecialKey()){
14486 this.lastKey = e.getKey();
14487 this.dqTask.delay(this.queryDelay);
14492 validateBlur : function(){
14493 return !this.list || !this.list.isVisible();
14497 initQuery : function(){
14499 var v = this.getRawValue();
14501 if(this.tickable && this.editable){
14502 v = this.tickableInputEl().getValue();
14509 doForce : function(){
14510 if(this.inputEl().dom.value.length > 0){
14511 this.inputEl().dom.value =
14512 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14518 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14519 * query allowing the query action to be canceled if needed.
14520 * @param {String} query The SQL query to execute
14521 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14522 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14523 * saved in the current store (defaults to false)
14525 doQuery : function(q, forceAll){
14527 if(q === undefined || q === null){
14532 forceAll: forceAll,
14536 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14541 forceAll = qe.forceAll;
14542 if(forceAll === true || (q.length >= this.minChars)){
14544 this.hasQuery = true;
14546 if(this.lastQuery != q || this.alwaysQuery){
14547 this.lastQuery = q;
14548 if(this.mode == 'local'){
14549 this.selectedIndex = -1;
14551 this.store.clearFilter();
14554 if(this.specialFilter){
14555 this.fireEvent('specialfilter', this);
14560 this.store.filter(this.displayField, q);
14563 this.store.fireEvent("datachanged", this.store);
14570 this.store.baseParams[this.queryParam] = q;
14572 var options = {params : this.getParams(q)};
14575 options.add = true;
14576 options.params.start = this.page * this.pageSize;
14579 this.store.load(options);
14582 * this code will make the page width larger, at the beginning, the list not align correctly,
14583 * we should expand the list on onLoad
14584 * so command out it
14589 this.selectedIndex = -1;
14594 this.loadNext = false;
14598 getParams : function(q){
14600 //p[this.queryParam] = q;
14604 p.limit = this.pageSize;
14610 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14612 collapse : function(){
14613 if(!this.isExpanded()){
14619 this.hasFocus = false;
14623 this.cancelBtn.hide();
14624 this.trigger.show();
14627 this.tickableInputEl().dom.value = '';
14628 this.tickableInputEl().blur();
14633 Roo.get(document).un('mousedown', this.collapseIf, this);
14634 Roo.get(document).un('mousewheel', this.collapseIf, this);
14635 if (!this.editable) {
14636 Roo.get(document).un('keydown', this.listKeyPress, this);
14638 this.fireEvent('collapse', this);
14644 collapseIf : function(e){
14645 var in_combo = e.within(this.el);
14646 var in_list = e.within(this.list);
14647 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14649 if (in_combo || in_list || is_list) {
14650 //e.stopPropagation();
14655 this.onTickableFooterButtonClick(e, false, false);
14663 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14665 expand : function(){
14667 if(this.isExpanded() || !this.hasFocus){
14671 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14672 this.list.setWidth(lw);
14678 this.restrictHeight();
14682 this.tickItems = Roo.apply([], this.item);
14685 this.cancelBtn.show();
14686 this.trigger.hide();
14689 this.tickableInputEl().focus();
14694 Roo.get(document).on('mousedown', this.collapseIf, this);
14695 Roo.get(document).on('mousewheel', this.collapseIf, this);
14696 if (!this.editable) {
14697 Roo.get(document).on('keydown', this.listKeyPress, this);
14700 this.fireEvent('expand', this);
14704 // Implements the default empty TriggerField.onTriggerClick function
14705 onTriggerClick : function(e)
14707 Roo.log('trigger click');
14709 if(this.disabled || !this.triggerList){
14714 this.loadNext = false;
14716 if(this.isExpanded()){
14718 if (!this.blockFocus) {
14719 this.inputEl().focus();
14723 this.hasFocus = true;
14724 if(this.triggerAction == 'all') {
14725 this.doQuery(this.allQuery, true);
14727 this.doQuery(this.getRawValue());
14729 if (!this.blockFocus) {
14730 this.inputEl().focus();
14735 onTickableTriggerClick : function(e)
14742 this.loadNext = false;
14743 this.hasFocus = true;
14745 if(this.triggerAction == 'all') {
14746 this.doQuery(this.allQuery, true);
14748 this.doQuery(this.getRawValue());
14752 onSearchFieldClick : function(e)
14754 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14755 this.onTickableFooterButtonClick(e, false, false);
14759 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14764 this.loadNext = false;
14765 this.hasFocus = true;
14767 if(this.triggerAction == 'all') {
14768 this.doQuery(this.allQuery, true);
14770 this.doQuery(this.getRawValue());
14774 listKeyPress : function(e)
14776 //Roo.log('listkeypress');
14777 // scroll to first matching element based on key pres..
14778 if (e.isSpecialKey()) {
14781 var k = String.fromCharCode(e.getKey()).toUpperCase();
14784 var csel = this.view.getSelectedNodes();
14785 var cselitem = false;
14787 var ix = this.view.indexOf(csel[0]);
14788 cselitem = this.store.getAt(ix);
14789 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14795 this.store.each(function(v) {
14797 // start at existing selection.
14798 if (cselitem.id == v.id) {
14804 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14805 match = this.store.indexOf(v);
14811 if (match === false) {
14812 return true; // no more action?
14815 this.view.select(match);
14816 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14817 sn.scrollIntoView(sn.dom.parentNode, false);
14820 onViewScroll : function(e, t){
14822 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){
14826 this.hasQuery = true;
14828 this.loading = this.list.select('.loading', true).first();
14830 if(this.loading === null){
14831 this.list.createChild({
14833 cls: 'loading roo-select2-more-results roo-select2-active',
14834 html: 'Loading more results...'
14837 this.loading = this.list.select('.loading', true).first();
14839 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14841 this.loading.hide();
14844 this.loading.show();
14849 this.loadNext = true;
14851 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14856 addItem : function(o)
14858 var dv = ''; // display value
14860 if (this.displayField) {
14861 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14863 // this is an error condition!!!
14864 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14871 var choice = this.choices.createChild({
14873 cls: 'roo-select2-search-choice',
14882 cls: 'roo-select2-search-choice-close fa fa-times',
14887 }, this.searchField);
14889 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14891 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14899 this.inputEl().dom.value = '';
14904 onRemoveItem : function(e, _self, o)
14906 e.preventDefault();
14908 this.lastItem = Roo.apply([], this.item);
14910 var index = this.item.indexOf(o.data) * 1;
14913 Roo.log('not this item?!');
14917 this.item.splice(index, 1);
14922 this.fireEvent('remove', this, e);
14928 syncValue : function()
14930 if(!this.item.length){
14937 Roo.each(this.item, function(i){
14938 if(_this.valueField){
14939 value.push(i[_this.valueField]);
14946 this.value = value.join(',');
14948 if(this.hiddenField){
14949 this.hiddenField.dom.value = this.value;
14952 this.store.fireEvent("datachanged", this.store);
14957 clearItem : function()
14959 if(!this.multiple){
14965 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14973 if(this.tickable && !Roo.isTouch){
14974 this.view.refresh();
14978 inputEl: function ()
14980 if(Roo.isIOS && this.useNativeIOS){
14981 return this.el.select('select.roo-ios-select', true).first();
14984 if(Roo.isTouch && this.mobileTouchView){
14985 return this.el.select('input.form-control',true).first();
14989 return this.searchField;
14992 return this.el.select('input.form-control',true).first();
14995 onTickableFooterButtonClick : function(e, btn, el)
14997 e.preventDefault();
14999 this.lastItem = Roo.apply([], this.item);
15001 if(btn && btn.name == 'cancel'){
15002 this.tickItems = Roo.apply([], this.item);
15011 Roo.each(this.tickItems, function(o){
15019 validate : function()
15021 if(this.getVisibilityEl().hasClass('hidden')){
15025 var v = this.getRawValue();
15028 v = this.getValue();
15031 if(this.disabled || this.allowBlank || v.length){
15036 this.markInvalid();
15040 tickableInputEl : function()
15042 if(!this.tickable || !this.editable){
15043 return this.inputEl();
15046 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15050 getAutoCreateTouchView : function()
15055 cls: 'form-group' //input-group
15061 type : this.inputType,
15062 cls : 'form-control x-combo-noedit',
15063 autocomplete: 'new-password',
15064 placeholder : this.placeholder || '',
15069 input.name = this.name;
15073 input.cls += ' input-' + this.size;
15076 if (this.disabled) {
15077 input.disabled = true;
15088 inputblock.cls += ' input-group';
15090 inputblock.cn.unshift({
15092 cls : 'input-group-addon',
15097 if(this.removable && !this.multiple){
15098 inputblock.cls += ' roo-removable';
15100 inputblock.cn.push({
15103 cls : 'roo-combo-removable-btn close'
15107 if(this.hasFeedback && !this.allowBlank){
15109 inputblock.cls += ' has-feedback';
15111 inputblock.cn.push({
15113 cls: 'glyphicon form-control-feedback'
15120 inputblock.cls += (this.before) ? '' : ' input-group';
15122 inputblock.cn.push({
15124 cls : 'input-group-addon',
15135 cls: 'form-hidden-field'
15149 cls: 'form-hidden-field'
15153 cls: 'roo-select2-choices',
15157 cls: 'roo-select2-search-field',
15170 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15176 if(!this.multiple && this.showToggleBtn){
15183 if (this.caret != false) {
15186 cls: 'fa fa-' + this.caret
15193 cls : 'input-group-addon btn dropdown-toggle',
15198 cls: 'combobox-clear',
15212 combobox.cls += ' roo-select2-container-multi';
15215 var align = this.labelAlign || this.parentLabelAlign();
15217 if (align ==='left' && this.fieldLabel.length) {
15222 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15223 tooltip : 'This field is required'
15227 cls : 'control-label',
15228 html : this.fieldLabel
15239 var labelCfg = cfg.cn[1];
15240 var contentCfg = cfg.cn[2];
15243 if(this.indicatorpos == 'right'){
15248 cls : 'control-label',
15252 html : this.fieldLabel
15256 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15257 tooltip : 'This field is required'
15270 labelCfg = cfg.cn[0];
15271 contentCfg = cfg.cn[1];
15276 if(this.labelWidth > 12){
15277 labelCfg.style = "width: " + this.labelWidth + 'px';
15280 if(this.labelWidth < 13 && this.labelmd == 0){
15281 this.labelmd = this.labelWidth;
15284 if(this.labellg > 0){
15285 labelCfg.cls += ' col-lg-' + this.labellg;
15286 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15289 if(this.labelmd > 0){
15290 labelCfg.cls += ' col-md-' + this.labelmd;
15291 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15294 if(this.labelsm > 0){
15295 labelCfg.cls += ' col-sm-' + this.labelsm;
15296 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15299 if(this.labelxs > 0){
15300 labelCfg.cls += ' col-xs-' + this.labelxs;
15301 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15305 } else if ( this.fieldLabel.length) {
15309 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15310 tooltip : 'This field is required'
15314 cls : 'control-label',
15315 html : this.fieldLabel
15326 if(this.indicatorpos == 'right'){
15330 cls : 'control-label',
15331 html : this.fieldLabel,
15335 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15336 tooltip : 'This field is required'
15353 var settings = this;
15355 ['xs','sm','md','lg'].map(function(size){
15356 if (settings[size]) {
15357 cfg.cls += ' col-' + size + '-' + settings[size];
15364 initTouchView : function()
15366 this.renderTouchView();
15368 this.touchViewEl.on('scroll', function(){
15369 this.el.dom.scrollTop = 0;
15372 this.originalValue = this.getValue();
15374 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15376 this.inputEl().on("click", this.showTouchView, this);
15377 if (this.triggerEl) {
15378 this.triggerEl.on("click", this.showTouchView, this);
15382 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15383 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15385 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15387 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15388 this.store.on('load', this.onTouchViewLoad, this);
15389 this.store.on('loadexception', this.onTouchViewLoadException, this);
15391 if(this.hiddenName){
15393 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15395 this.hiddenField.dom.value =
15396 this.hiddenValue !== undefined ? this.hiddenValue :
15397 this.value !== undefined ? this.value : '';
15399 this.el.dom.removeAttribute('name');
15400 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15404 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15405 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15408 if(this.removable && !this.multiple){
15409 var close = this.closeTriggerEl();
15411 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15412 close.on('click', this.removeBtnClick, this, close);
15416 * fix the bug in Safari iOS8
15418 this.inputEl().on("focus", function(e){
15419 document.activeElement.blur();
15422 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15429 renderTouchView : function()
15431 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15432 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15434 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15435 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15437 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15438 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15439 this.touchViewBodyEl.setStyle('overflow', 'auto');
15441 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15442 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15444 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15445 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15449 showTouchView : function()
15455 this.touchViewHeaderEl.hide();
15457 if(this.modalTitle.length){
15458 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15459 this.touchViewHeaderEl.show();
15462 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15463 this.touchViewEl.show();
15465 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15467 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15468 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15470 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15472 if(this.modalTitle.length){
15473 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15476 this.touchViewBodyEl.setHeight(bodyHeight);
15480 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15482 this.touchViewEl.addClass('in');
15485 if(this._touchViewMask){
15486 Roo.get(document.body).addClass("x-body-masked");
15487 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15488 this._touchViewMask.setStyle('z-index', 10000);
15489 this._touchViewMask.addClass('show');
15492 this.doTouchViewQuery();
15496 hideTouchView : function()
15498 this.touchViewEl.removeClass('in');
15502 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15504 this.touchViewEl.setStyle('display', 'none');
15507 if(this._touchViewMask){
15508 this._touchViewMask.removeClass('show');
15509 Roo.get(document.body).removeClass("x-body-masked");
15513 setTouchViewValue : function()
15520 Roo.each(this.tickItems, function(o){
15525 this.hideTouchView();
15528 doTouchViewQuery : function()
15537 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15541 if(!this.alwaysQuery || this.mode == 'local'){
15542 this.onTouchViewLoad();
15549 onTouchViewBeforeLoad : function(combo,opts)
15555 onTouchViewLoad : function()
15557 if(this.store.getCount() < 1){
15558 this.onTouchViewEmptyResults();
15562 this.clearTouchView();
15564 var rawValue = this.getRawValue();
15566 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15568 this.tickItems = [];
15570 this.store.data.each(function(d, rowIndex){
15571 var row = this.touchViewListGroup.createChild(template);
15573 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15574 row.addClass(d.data.cls);
15577 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15580 html : d.data[this.displayField]
15583 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15584 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15587 row.removeClass('selected');
15588 if(!this.multiple && this.valueField &&
15589 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15592 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15593 row.addClass('selected');
15596 if(this.multiple && this.valueField &&
15597 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15601 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15602 this.tickItems.push(d.data);
15605 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15609 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15611 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15613 if(this.modalTitle.length){
15614 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15617 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15619 if(this.mobile_restrict_height && listHeight < bodyHeight){
15620 this.touchViewBodyEl.setHeight(listHeight);
15625 if(firstChecked && listHeight > bodyHeight){
15626 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15631 onTouchViewLoadException : function()
15633 this.hideTouchView();
15636 onTouchViewEmptyResults : function()
15638 this.clearTouchView();
15640 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15642 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15646 clearTouchView : function()
15648 this.touchViewListGroup.dom.innerHTML = '';
15651 onTouchViewClick : function(e, el, o)
15653 e.preventDefault();
15656 var rowIndex = o.rowIndex;
15658 var r = this.store.getAt(rowIndex);
15660 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15662 if(!this.multiple){
15663 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15664 c.dom.removeAttribute('checked');
15667 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15669 this.setFromData(r.data);
15671 var close = this.closeTriggerEl();
15677 this.hideTouchView();
15679 this.fireEvent('select', this, r, rowIndex);
15684 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15685 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15686 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15690 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15691 this.addItem(r.data);
15692 this.tickItems.push(r.data);
15696 getAutoCreateNativeIOS : function()
15699 cls: 'form-group' //input-group,
15704 cls : 'roo-ios-select'
15708 combobox.name = this.name;
15711 if (this.disabled) {
15712 combobox.disabled = true;
15715 var settings = this;
15717 ['xs','sm','md','lg'].map(function(size){
15718 if (settings[size]) {
15719 cfg.cls += ' col-' + size + '-' + settings[size];
15729 initIOSView : function()
15731 this.store.on('load', this.onIOSViewLoad, this);
15736 onIOSViewLoad : function()
15738 if(this.store.getCount() < 1){
15742 this.clearIOSView();
15744 if(this.allowBlank) {
15746 var default_text = '-- SELECT --';
15748 if(this.placeholder.length){
15749 default_text = this.placeholder;
15752 if(this.emptyTitle.length){
15753 default_text += ' - ' + this.emptyTitle + ' -';
15756 var opt = this.inputEl().createChild({
15759 html : default_text
15763 o[this.valueField] = 0;
15764 o[this.displayField] = default_text;
15766 this.ios_options.push({
15773 this.store.data.each(function(d, rowIndex){
15777 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15778 html = d.data[this.displayField];
15783 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15784 value = d.data[this.valueField];
15793 if(this.value == d.data[this.valueField]){
15794 option['selected'] = true;
15797 var opt = this.inputEl().createChild(option);
15799 this.ios_options.push({
15806 this.inputEl().on('change', function(){
15807 this.fireEvent('select', this);
15812 clearIOSView: function()
15814 this.inputEl().dom.innerHTML = '';
15816 this.ios_options = [];
15819 setIOSValue: function(v)
15823 if(!this.ios_options){
15827 Roo.each(this.ios_options, function(opts){
15829 opts.el.dom.removeAttribute('selected');
15831 if(opts.data[this.valueField] != v){
15835 opts.el.dom.setAttribute('selected', true);
15841 * @cfg {Boolean} grow
15845 * @cfg {Number} growMin
15849 * @cfg {Number} growMax
15858 Roo.apply(Roo.bootstrap.ComboBox, {
15862 cls: 'modal-header',
15884 cls: 'list-group-item',
15888 cls: 'roo-combobox-list-group-item-value'
15892 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15906 listItemCheckbox : {
15908 cls: 'list-group-item',
15912 cls: 'roo-combobox-list-group-item-value'
15916 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15932 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15937 cls: 'modal-footer',
15945 cls: 'col-xs-6 text-left',
15948 cls: 'btn btn-danger roo-touch-view-cancel',
15954 cls: 'col-xs-6 text-right',
15957 cls: 'btn btn-success roo-touch-view-ok',
15968 Roo.apply(Roo.bootstrap.ComboBox, {
15970 touchViewTemplate : {
15972 cls: 'modal fade roo-combobox-touch-view',
15976 cls: 'modal-dialog',
15977 style : 'position:fixed', // we have to fix position....
15981 cls: 'modal-content',
15983 Roo.bootstrap.ComboBox.header,
15984 Roo.bootstrap.ComboBox.body,
15985 Roo.bootstrap.ComboBox.footer
15994 * Ext JS Library 1.1.1
15995 * Copyright(c) 2006-2007, Ext JS, LLC.
15997 * Originally Released Under LGPL - original licence link has changed is not relivant.
16000 * <script type="text/javascript">
16005 * @extends Roo.util.Observable
16006 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16007 * This class also supports single and multi selection modes. <br>
16008 * Create a data model bound view:
16010 var store = new Roo.data.Store(...);
16012 var view = new Roo.View({
16014 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16016 singleSelect: true,
16017 selectedClass: "ydataview-selected",
16021 // listen for node click?
16022 view.on("click", function(vw, index, node, e){
16023 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16027 dataModel.load("foobar.xml");
16029 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16031 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16032 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16034 * Note: old style constructor is still suported (container, template, config)
16037 * Create a new View
16038 * @param {Object} config The config object
16041 Roo.View = function(config, depreciated_tpl, depreciated_config){
16043 this.parent = false;
16045 if (typeof(depreciated_tpl) == 'undefined') {
16046 // new way.. - universal constructor.
16047 Roo.apply(this, config);
16048 this.el = Roo.get(this.el);
16051 this.el = Roo.get(config);
16052 this.tpl = depreciated_tpl;
16053 Roo.apply(this, depreciated_config);
16055 this.wrapEl = this.el.wrap().wrap();
16056 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16059 if(typeof(this.tpl) == "string"){
16060 this.tpl = new Roo.Template(this.tpl);
16062 // support xtype ctors..
16063 this.tpl = new Roo.factory(this.tpl, Roo);
16067 this.tpl.compile();
16072 * @event beforeclick
16073 * Fires before a click is processed. Returns false to cancel the default action.
16074 * @param {Roo.View} this
16075 * @param {Number} index The index of the target node
16076 * @param {HTMLElement} node The target node
16077 * @param {Roo.EventObject} e The raw event object
16079 "beforeclick" : true,
16082 * Fires when a template node is clicked.
16083 * @param {Roo.View} this
16084 * @param {Number} index The index of the target node
16085 * @param {HTMLElement} node The target node
16086 * @param {Roo.EventObject} e The raw event object
16091 * Fires when a template node is double clicked.
16092 * @param {Roo.View} this
16093 * @param {Number} index The index of the target node
16094 * @param {HTMLElement} node The target node
16095 * @param {Roo.EventObject} e The raw event object
16099 * @event contextmenu
16100 * Fires when a template node is right clicked.
16101 * @param {Roo.View} this
16102 * @param {Number} index The index of the target node
16103 * @param {HTMLElement} node The target node
16104 * @param {Roo.EventObject} e The raw event object
16106 "contextmenu" : true,
16108 * @event selectionchange
16109 * Fires when the selected nodes change.
16110 * @param {Roo.View} this
16111 * @param {Array} selections Array of the selected nodes
16113 "selectionchange" : true,
16116 * @event beforeselect
16117 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16118 * @param {Roo.View} this
16119 * @param {HTMLElement} node The node to be selected
16120 * @param {Array} selections Array of currently selected nodes
16122 "beforeselect" : true,
16124 * @event preparedata
16125 * Fires on every row to render, to allow you to change the data.
16126 * @param {Roo.View} this
16127 * @param {Object} data to be rendered (change this)
16129 "preparedata" : true
16137 "click": this.onClick,
16138 "dblclick": this.onDblClick,
16139 "contextmenu": this.onContextMenu,
16143 this.selections = [];
16145 this.cmp = new Roo.CompositeElementLite([]);
16147 this.store = Roo.factory(this.store, Roo.data);
16148 this.setStore(this.store, true);
16151 if ( this.footer && this.footer.xtype) {
16153 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16155 this.footer.dataSource = this.store;
16156 this.footer.container = fctr;
16157 this.footer = Roo.factory(this.footer, Roo);
16158 fctr.insertFirst(this.el);
16160 // this is a bit insane - as the paging toolbar seems to detach the el..
16161 // dom.parentNode.parentNode.parentNode
16162 // they get detached?
16166 Roo.View.superclass.constructor.call(this);
16171 Roo.extend(Roo.View, Roo.util.Observable, {
16174 * @cfg {Roo.data.Store} store Data store to load data from.
16179 * @cfg {String|Roo.Element} el The container element.
16184 * @cfg {String|Roo.Template} tpl The template used by this View
16188 * @cfg {String} dataName the named area of the template to use as the data area
16189 * Works with domtemplates roo-name="name"
16193 * @cfg {String} selectedClass The css class to add to selected nodes
16195 selectedClass : "x-view-selected",
16197 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16202 * @cfg {String} text to display on mask (default Loading)
16206 * @cfg {Boolean} multiSelect Allow multiple selection
16208 multiSelect : false,
16210 * @cfg {Boolean} singleSelect Allow single selection
16212 singleSelect: false,
16215 * @cfg {Boolean} toggleSelect - selecting
16217 toggleSelect : false,
16220 * @cfg {Boolean} tickable - selecting
16225 * Returns the element this view is bound to.
16226 * @return {Roo.Element}
16228 getEl : function(){
16229 return this.wrapEl;
16235 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16237 refresh : function(){
16238 //Roo.log('refresh');
16241 // if we are using something like 'domtemplate', then
16242 // the what gets used is:
16243 // t.applySubtemplate(NAME, data, wrapping data..)
16244 // the outer template then get' applied with
16245 // the store 'extra data'
16246 // and the body get's added to the
16247 // roo-name="data" node?
16248 // <span class='roo-tpl-{name}'></span> ?????
16252 this.clearSelections();
16253 this.el.update("");
16255 var records = this.store.getRange();
16256 if(records.length < 1) {
16258 // is this valid?? = should it render a template??
16260 this.el.update(this.emptyText);
16264 if (this.dataName) {
16265 this.el.update(t.apply(this.store.meta)); //????
16266 el = this.el.child('.roo-tpl-' + this.dataName);
16269 for(var i = 0, len = records.length; i < len; i++){
16270 var data = this.prepareData(records[i].data, i, records[i]);
16271 this.fireEvent("preparedata", this, data, i, records[i]);
16273 var d = Roo.apply({}, data);
16276 Roo.apply(d, {'roo-id' : Roo.id()});
16280 Roo.each(this.parent.item, function(item){
16281 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16284 Roo.apply(d, {'roo-data-checked' : 'checked'});
16288 html[html.length] = Roo.util.Format.trim(
16290 t.applySubtemplate(this.dataName, d, this.store.meta) :
16297 el.update(html.join(""));
16298 this.nodes = el.dom.childNodes;
16299 this.updateIndexes(0);
16304 * Function to override to reformat the data that is sent to
16305 * the template for each node.
16306 * DEPRICATED - use the preparedata event handler.
16307 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16308 * a JSON object for an UpdateManager bound view).
16310 prepareData : function(data, index, record)
16312 this.fireEvent("preparedata", this, data, index, record);
16316 onUpdate : function(ds, record){
16317 // Roo.log('on update');
16318 this.clearSelections();
16319 var index = this.store.indexOf(record);
16320 var n = this.nodes[index];
16321 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16322 n.parentNode.removeChild(n);
16323 this.updateIndexes(index, index);
16329 onAdd : function(ds, records, index)
16331 //Roo.log(['on Add', ds, records, index] );
16332 this.clearSelections();
16333 if(this.nodes.length == 0){
16337 var n = this.nodes[index];
16338 for(var i = 0, len = records.length; i < len; i++){
16339 var d = this.prepareData(records[i].data, i, records[i]);
16341 this.tpl.insertBefore(n, d);
16344 this.tpl.append(this.el, d);
16347 this.updateIndexes(index);
16350 onRemove : function(ds, record, index){
16351 // Roo.log('onRemove');
16352 this.clearSelections();
16353 var el = this.dataName ?
16354 this.el.child('.roo-tpl-' + this.dataName) :
16357 el.dom.removeChild(this.nodes[index]);
16358 this.updateIndexes(index);
16362 * Refresh an individual node.
16363 * @param {Number} index
16365 refreshNode : function(index){
16366 this.onUpdate(this.store, this.store.getAt(index));
16369 updateIndexes : function(startIndex, endIndex){
16370 var ns = this.nodes;
16371 startIndex = startIndex || 0;
16372 endIndex = endIndex || ns.length - 1;
16373 for(var i = startIndex; i <= endIndex; i++){
16374 ns[i].nodeIndex = i;
16379 * Changes the data store this view uses and refresh the view.
16380 * @param {Store} store
16382 setStore : function(store, initial){
16383 if(!initial && this.store){
16384 this.store.un("datachanged", this.refresh);
16385 this.store.un("add", this.onAdd);
16386 this.store.un("remove", this.onRemove);
16387 this.store.un("update", this.onUpdate);
16388 this.store.un("clear", this.refresh);
16389 this.store.un("beforeload", this.onBeforeLoad);
16390 this.store.un("load", this.onLoad);
16391 this.store.un("loadexception", this.onLoad);
16395 store.on("datachanged", this.refresh, this);
16396 store.on("add", this.onAdd, this);
16397 store.on("remove", this.onRemove, this);
16398 store.on("update", this.onUpdate, this);
16399 store.on("clear", this.refresh, this);
16400 store.on("beforeload", this.onBeforeLoad, this);
16401 store.on("load", this.onLoad, this);
16402 store.on("loadexception", this.onLoad, this);
16410 * onbeforeLoad - masks the loading area.
16413 onBeforeLoad : function(store,opts)
16415 //Roo.log('onBeforeLoad');
16417 this.el.update("");
16419 this.el.mask(this.mask ? this.mask : "Loading" );
16421 onLoad : function ()
16428 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16429 * @param {HTMLElement} node
16430 * @return {HTMLElement} The template node
16432 findItemFromChild : function(node){
16433 var el = this.dataName ?
16434 this.el.child('.roo-tpl-' + this.dataName,true) :
16437 if(!node || node.parentNode == el){
16440 var p = node.parentNode;
16441 while(p && p != el){
16442 if(p.parentNode == el){
16451 onClick : function(e){
16452 var item = this.findItemFromChild(e.getTarget());
16454 var index = this.indexOf(item);
16455 if(this.onItemClick(item, index, e) !== false){
16456 this.fireEvent("click", this, index, item, e);
16459 this.clearSelections();
16464 onContextMenu : function(e){
16465 var item = this.findItemFromChild(e.getTarget());
16467 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16472 onDblClick : function(e){
16473 var item = this.findItemFromChild(e.getTarget());
16475 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16479 onItemClick : function(item, index, e)
16481 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16484 if (this.toggleSelect) {
16485 var m = this.isSelected(item) ? 'unselect' : 'select';
16488 _t[m](item, true, false);
16491 if(this.multiSelect || this.singleSelect){
16492 if(this.multiSelect && e.shiftKey && this.lastSelection){
16493 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16495 this.select(item, this.multiSelect && e.ctrlKey);
16496 this.lastSelection = item;
16499 if(!this.tickable){
16500 e.preventDefault();
16508 * Get the number of selected nodes.
16511 getSelectionCount : function(){
16512 return this.selections.length;
16516 * Get the currently selected nodes.
16517 * @return {Array} An array of HTMLElements
16519 getSelectedNodes : function(){
16520 return this.selections;
16524 * Get the indexes of the selected nodes.
16527 getSelectedIndexes : function(){
16528 var indexes = [], s = this.selections;
16529 for(var i = 0, len = s.length; i < len; i++){
16530 indexes.push(s[i].nodeIndex);
16536 * Clear all selections
16537 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16539 clearSelections : function(suppressEvent){
16540 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16541 this.cmp.elements = this.selections;
16542 this.cmp.removeClass(this.selectedClass);
16543 this.selections = [];
16544 if(!suppressEvent){
16545 this.fireEvent("selectionchange", this, this.selections);
16551 * Returns true if the passed node is selected
16552 * @param {HTMLElement/Number} node The node or node index
16553 * @return {Boolean}
16555 isSelected : function(node){
16556 var s = this.selections;
16560 node = this.getNode(node);
16561 return s.indexOf(node) !== -1;
16566 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16567 * @param {Boolean} keepExisting (optional) true to keep existing selections
16568 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16570 select : function(nodeInfo, keepExisting, suppressEvent){
16571 if(nodeInfo instanceof Array){
16573 this.clearSelections(true);
16575 for(var i = 0, len = nodeInfo.length; i < len; i++){
16576 this.select(nodeInfo[i], true, true);
16580 var node = this.getNode(nodeInfo);
16581 if(!node || this.isSelected(node)){
16582 return; // already selected.
16585 this.clearSelections(true);
16588 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16589 Roo.fly(node).addClass(this.selectedClass);
16590 this.selections.push(node);
16591 if(!suppressEvent){
16592 this.fireEvent("selectionchange", this, this.selections);
16600 * @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
16601 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16602 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16604 unselect : function(nodeInfo, keepExisting, suppressEvent)
16606 if(nodeInfo instanceof Array){
16607 Roo.each(this.selections, function(s) {
16608 this.unselect(s, nodeInfo);
16612 var node = this.getNode(nodeInfo);
16613 if(!node || !this.isSelected(node)){
16614 //Roo.log("not selected");
16615 return; // not selected.
16619 Roo.each(this.selections, function(s) {
16621 Roo.fly(node).removeClass(this.selectedClass);
16628 this.selections= ns;
16629 this.fireEvent("selectionchange", this, this.selections);
16633 * Gets a template node.
16634 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16635 * @return {HTMLElement} The node or null if it wasn't found
16637 getNode : function(nodeInfo){
16638 if(typeof nodeInfo == "string"){
16639 return document.getElementById(nodeInfo);
16640 }else if(typeof nodeInfo == "number"){
16641 return this.nodes[nodeInfo];
16647 * Gets a range template nodes.
16648 * @param {Number} startIndex
16649 * @param {Number} endIndex
16650 * @return {Array} An array of nodes
16652 getNodes : function(start, end){
16653 var ns = this.nodes;
16654 start = start || 0;
16655 end = typeof end == "undefined" ? ns.length - 1 : end;
16658 for(var i = start; i <= end; i++){
16662 for(var i = start; i >= end; i--){
16670 * Finds the index of the passed node
16671 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16672 * @return {Number} The index of the node or -1
16674 indexOf : function(node){
16675 node = this.getNode(node);
16676 if(typeof node.nodeIndex == "number"){
16677 return node.nodeIndex;
16679 var ns = this.nodes;
16680 for(var i = 0, len = ns.length; i < len; i++){
16691 * based on jquery fullcalendar
16695 Roo.bootstrap = Roo.bootstrap || {};
16697 * @class Roo.bootstrap.Calendar
16698 * @extends Roo.bootstrap.Component
16699 * Bootstrap Calendar class
16700 * @cfg {Boolean} loadMask (true|false) default false
16701 * @cfg {Object} header generate the user specific header of the calendar, default false
16704 * Create a new Container
16705 * @param {Object} config The config object
16710 Roo.bootstrap.Calendar = function(config){
16711 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16715 * Fires when a date is selected
16716 * @param {DatePicker} this
16717 * @param {Date} date The selected date
16721 * @event monthchange
16722 * Fires when the displayed month changes
16723 * @param {DatePicker} this
16724 * @param {Date} date The selected month
16726 'monthchange': true,
16728 * @event evententer
16729 * Fires when mouse over an event
16730 * @param {Calendar} this
16731 * @param {event} Event
16733 'evententer': true,
16735 * @event eventleave
16736 * Fires when the mouse leaves an
16737 * @param {Calendar} this
16740 'eventleave': true,
16742 * @event eventclick
16743 * Fires when the mouse click an
16744 * @param {Calendar} this
16753 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16756 * @cfg {Number} startDay
16757 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16765 getAutoCreate : function(){
16768 var fc_button = function(name, corner, style, content ) {
16769 return Roo.apply({},{
16771 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16773 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16776 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16787 style : 'width:100%',
16794 cls : 'fc-header-left',
16796 fc_button('prev', 'left', 'arrow', '‹' ),
16797 fc_button('next', 'right', 'arrow', '›' ),
16798 { tag: 'span', cls: 'fc-header-space' },
16799 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16807 cls : 'fc-header-center',
16811 cls: 'fc-header-title',
16814 html : 'month / year'
16822 cls : 'fc-header-right',
16824 /* fc_button('month', 'left', '', 'month' ),
16825 fc_button('week', '', '', 'week' ),
16826 fc_button('day', 'right', '', 'day' )
16838 header = this.header;
16841 var cal_heads = function() {
16843 // fixme - handle this.
16845 for (var i =0; i < Date.dayNames.length; i++) {
16846 var d = Date.dayNames[i];
16849 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16850 html : d.substring(0,3)
16854 ret[0].cls += ' fc-first';
16855 ret[6].cls += ' fc-last';
16858 var cal_cell = function(n) {
16861 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16866 cls: 'fc-day-number',
16870 cls: 'fc-day-content',
16874 style: 'position: relative;' // height: 17px;
16886 var cal_rows = function() {
16889 for (var r = 0; r < 6; r++) {
16896 for (var i =0; i < Date.dayNames.length; i++) {
16897 var d = Date.dayNames[i];
16898 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16901 row.cn[0].cls+=' fc-first';
16902 row.cn[0].cn[0].style = 'min-height:90px';
16903 row.cn[6].cls+=' fc-last';
16907 ret[0].cls += ' fc-first';
16908 ret[4].cls += ' fc-prev-last';
16909 ret[5].cls += ' fc-last';
16916 cls: 'fc-border-separate',
16917 style : 'width:100%',
16925 cls : 'fc-first fc-last',
16943 cls : 'fc-content',
16944 style : "position: relative;",
16947 cls : 'fc-view fc-view-month fc-grid',
16948 style : 'position: relative',
16949 unselectable : 'on',
16952 cls : 'fc-event-container',
16953 style : 'position:absolute;z-index:8;top:0;left:0;'
16971 initEvents : function()
16974 throw "can not find store for calendar";
16980 style: "text-align:center",
16984 style: "background-color:white;width:50%;margin:250 auto",
16988 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16999 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17001 var size = this.el.select('.fc-content', true).first().getSize();
17002 this.maskEl.setSize(size.width, size.height);
17003 this.maskEl.enableDisplayMode("block");
17004 if(!this.loadMask){
17005 this.maskEl.hide();
17008 this.store = Roo.factory(this.store, Roo.data);
17009 this.store.on('load', this.onLoad, this);
17010 this.store.on('beforeload', this.onBeforeLoad, this);
17014 this.cells = this.el.select('.fc-day',true);
17015 //Roo.log(this.cells);
17016 this.textNodes = this.el.query('.fc-day-number');
17017 this.cells.addClassOnOver('fc-state-hover');
17019 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17020 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17021 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17022 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17024 this.on('monthchange', this.onMonthChange, this);
17026 this.update(new Date().clearTime());
17029 resize : function() {
17030 var sz = this.el.getSize();
17032 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17033 this.el.select('.fc-day-content div',true).setHeight(34);
17038 showPrevMonth : function(e){
17039 this.update(this.activeDate.add("mo", -1));
17041 showToday : function(e){
17042 this.update(new Date().clearTime());
17045 showNextMonth : function(e){
17046 this.update(this.activeDate.add("mo", 1));
17050 showPrevYear : function(){
17051 this.update(this.activeDate.add("y", -1));
17055 showNextYear : function(){
17056 this.update(this.activeDate.add("y", 1));
17061 update : function(date)
17063 var vd = this.activeDate;
17064 this.activeDate = date;
17065 // if(vd && this.el){
17066 // var t = date.getTime();
17067 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17068 // Roo.log('using add remove');
17070 // this.fireEvent('monthchange', this, date);
17072 // this.cells.removeClass("fc-state-highlight");
17073 // this.cells.each(function(c){
17074 // if(c.dateValue == t){
17075 // c.addClass("fc-state-highlight");
17076 // setTimeout(function(){
17077 // try{c.dom.firstChild.focus();}catch(e){}
17087 var days = date.getDaysInMonth();
17089 var firstOfMonth = date.getFirstDateOfMonth();
17090 var startingPos = firstOfMonth.getDay()-this.startDay;
17092 if(startingPos < this.startDay){
17096 var pm = date.add(Date.MONTH, -1);
17097 var prevStart = pm.getDaysInMonth()-startingPos;
17099 this.cells = this.el.select('.fc-day',true);
17100 this.textNodes = this.el.query('.fc-day-number');
17101 this.cells.addClassOnOver('fc-state-hover');
17103 var cells = this.cells.elements;
17104 var textEls = this.textNodes;
17106 Roo.each(cells, function(cell){
17107 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17110 days += startingPos;
17112 // convert everything to numbers so it's fast
17113 var day = 86400000;
17114 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17117 //Roo.log(prevStart);
17119 var today = new Date().clearTime().getTime();
17120 var sel = date.clearTime().getTime();
17121 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17122 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17123 var ddMatch = this.disabledDatesRE;
17124 var ddText = this.disabledDatesText;
17125 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17126 var ddaysText = this.disabledDaysText;
17127 var format = this.format;
17129 var setCellClass = function(cal, cell){
17133 //Roo.log('set Cell Class');
17135 var t = d.getTime();
17139 cell.dateValue = t;
17141 cell.className += " fc-today";
17142 cell.className += " fc-state-highlight";
17143 cell.title = cal.todayText;
17146 // disable highlight in other month..
17147 //cell.className += " fc-state-highlight";
17152 cell.className = " fc-state-disabled";
17153 cell.title = cal.minText;
17157 cell.className = " fc-state-disabled";
17158 cell.title = cal.maxText;
17162 if(ddays.indexOf(d.getDay()) != -1){
17163 cell.title = ddaysText;
17164 cell.className = " fc-state-disabled";
17167 if(ddMatch && format){
17168 var fvalue = d.dateFormat(format);
17169 if(ddMatch.test(fvalue)){
17170 cell.title = ddText.replace("%0", fvalue);
17171 cell.className = " fc-state-disabled";
17175 if (!cell.initialClassName) {
17176 cell.initialClassName = cell.dom.className;
17179 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17184 for(; i < startingPos; i++) {
17185 textEls[i].innerHTML = (++prevStart);
17186 d.setDate(d.getDate()+1);
17188 cells[i].className = "fc-past fc-other-month";
17189 setCellClass(this, cells[i]);
17194 for(; i < days; i++){
17195 intDay = i - startingPos + 1;
17196 textEls[i].innerHTML = (intDay);
17197 d.setDate(d.getDate()+1);
17199 cells[i].className = ''; // "x-date-active";
17200 setCellClass(this, cells[i]);
17204 for(; i < 42; i++) {
17205 textEls[i].innerHTML = (++extraDays);
17206 d.setDate(d.getDate()+1);
17208 cells[i].className = "fc-future fc-other-month";
17209 setCellClass(this, cells[i]);
17212 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17214 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17216 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17217 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17219 if(totalRows != 6){
17220 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17221 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17224 this.fireEvent('monthchange', this, date);
17228 if(!this.internalRender){
17229 var main = this.el.dom.firstChild;
17230 var w = main.offsetWidth;
17231 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17232 Roo.fly(main).setWidth(w);
17233 this.internalRender = true;
17234 // opera does not respect the auto grow header center column
17235 // then, after it gets a width opera refuses to recalculate
17236 // without a second pass
17237 if(Roo.isOpera && !this.secondPass){
17238 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17239 this.secondPass = true;
17240 this.update.defer(10, this, [date]);
17247 findCell : function(dt) {
17248 dt = dt.clearTime().getTime();
17250 this.cells.each(function(c){
17251 //Roo.log("check " +c.dateValue + '?=' + dt);
17252 if(c.dateValue == dt){
17262 findCells : function(ev) {
17263 var s = ev.start.clone().clearTime().getTime();
17265 var e= ev.end.clone().clearTime().getTime();
17268 this.cells.each(function(c){
17269 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17271 if(c.dateValue > e){
17274 if(c.dateValue < s){
17283 // findBestRow: function(cells)
17287 // for (var i =0 ; i < cells.length;i++) {
17288 // ret = Math.max(cells[i].rows || 0,ret);
17295 addItem : function(ev)
17297 // look for vertical location slot in
17298 var cells = this.findCells(ev);
17300 // ev.row = this.findBestRow(cells);
17302 // work out the location.
17306 for(var i =0; i < cells.length; i++) {
17308 cells[i].row = cells[0].row;
17311 cells[i].row = cells[i].row + 1;
17321 if (crow.start.getY() == cells[i].getY()) {
17323 crow.end = cells[i];
17340 cells[0].events.push(ev);
17342 this.calevents.push(ev);
17345 clearEvents: function() {
17347 if(!this.calevents){
17351 Roo.each(this.cells.elements, function(c){
17357 Roo.each(this.calevents, function(e) {
17358 Roo.each(e.els, function(el) {
17359 el.un('mouseenter' ,this.onEventEnter, this);
17360 el.un('mouseleave' ,this.onEventLeave, this);
17365 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17371 renderEvents: function()
17375 this.cells.each(function(c) {
17384 if(c.row != c.events.length){
17385 r = 4 - (4 - (c.row - c.events.length));
17388 c.events = ev.slice(0, r);
17389 c.more = ev.slice(r);
17391 if(c.more.length && c.more.length == 1){
17392 c.events.push(c.more.pop());
17395 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17399 this.cells.each(function(c) {
17401 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17404 for (var e = 0; e < c.events.length; e++){
17405 var ev = c.events[e];
17406 var rows = ev.rows;
17408 for(var i = 0; i < rows.length; i++) {
17410 // how many rows should it span..
17413 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17414 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17416 unselectable : "on",
17419 cls: 'fc-event-inner',
17423 // cls: 'fc-event-time',
17424 // html : cells.length > 1 ? '' : ev.time
17428 cls: 'fc-event-title',
17429 html : String.format('{0}', ev.title)
17436 cls: 'ui-resizable-handle ui-resizable-e',
17437 html : '  '
17444 cfg.cls += ' fc-event-start';
17446 if ((i+1) == rows.length) {
17447 cfg.cls += ' fc-event-end';
17450 var ctr = _this.el.select('.fc-event-container',true).first();
17451 var cg = ctr.createChild(cfg);
17453 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17454 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17456 var r = (c.more.length) ? 1 : 0;
17457 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17458 cg.setWidth(ebox.right - sbox.x -2);
17460 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17461 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17462 cg.on('click', _this.onEventClick, _this, ev);
17473 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17474 style : 'position: absolute',
17475 unselectable : "on",
17478 cls: 'fc-event-inner',
17482 cls: 'fc-event-title',
17490 cls: 'ui-resizable-handle ui-resizable-e',
17491 html : '  '
17497 var ctr = _this.el.select('.fc-event-container',true).first();
17498 var cg = ctr.createChild(cfg);
17500 var sbox = c.select('.fc-day-content',true).first().getBox();
17501 var ebox = c.select('.fc-day-content',true).first().getBox();
17503 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17504 cg.setWidth(ebox.right - sbox.x -2);
17506 cg.on('click', _this.onMoreEventClick, _this, c.more);
17516 onEventEnter: function (e, el,event,d) {
17517 this.fireEvent('evententer', this, el, event);
17520 onEventLeave: function (e, el,event,d) {
17521 this.fireEvent('eventleave', this, el, event);
17524 onEventClick: function (e, el,event,d) {
17525 this.fireEvent('eventclick', this, el, event);
17528 onMonthChange: function () {
17532 onMoreEventClick: function(e, el, more)
17536 this.calpopover.placement = 'right';
17537 this.calpopover.setTitle('More');
17539 this.calpopover.setContent('');
17541 var ctr = this.calpopover.el.select('.popover-content', true).first();
17543 Roo.each(more, function(m){
17545 cls : 'fc-event-hori fc-event-draggable',
17548 var cg = ctr.createChild(cfg);
17550 cg.on('click', _this.onEventClick, _this, m);
17553 this.calpopover.show(el);
17558 onLoad: function ()
17560 this.calevents = [];
17563 if(this.store.getCount() > 0){
17564 this.store.data.each(function(d){
17567 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17568 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17569 time : d.data.start_time,
17570 title : d.data.title,
17571 description : d.data.description,
17572 venue : d.data.venue
17577 this.renderEvents();
17579 if(this.calevents.length && this.loadMask){
17580 this.maskEl.hide();
17584 onBeforeLoad: function()
17586 this.clearEvents();
17588 this.maskEl.show();
17602 * @class Roo.bootstrap.Popover
17603 * @extends Roo.bootstrap.Component
17604 * Bootstrap Popover class
17605 * @cfg {String} html contents of the popover (or false to use children..)
17606 * @cfg {String} title of popover (or false to hide)
17607 * @cfg {String} placement how it is placed
17608 * @cfg {String} trigger click || hover (or false to trigger manually)
17609 * @cfg {String} over what (parent or false to trigger manually.)
17610 * @cfg {Number} delay - delay before showing
17613 * Create a new Popover
17614 * @param {Object} config The config object
17617 Roo.bootstrap.Popover = function(config){
17618 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17624 * After the popover show
17626 * @param {Roo.bootstrap.Popover} this
17631 * After the popover hide
17633 * @param {Roo.bootstrap.Popover} this
17639 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17641 title: 'Fill in a title',
17644 placement : 'right',
17645 trigger : 'hover', // hover
17651 can_build_overlaid : false,
17653 getChildContainer : function()
17655 return this.el.select('.popover-content',true).first();
17658 getAutoCreate : function(){
17661 cls : 'popover roo-dynamic',
17662 style: 'display:block',
17668 cls : 'popover-inner',
17672 cls: 'popover-title popover-header',
17676 cls : 'popover-content popover-body',
17687 setTitle: function(str)
17690 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17692 setContent: function(str)
17695 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17697 // as it get's added to the bottom of the page.
17698 onRender : function(ct, position)
17700 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17702 var cfg = Roo.apply({}, this.getAutoCreate());
17706 cfg.cls += ' ' + this.cls;
17709 cfg.style = this.style;
17711 //Roo.log("adding to ");
17712 this.el = Roo.get(document.body).createChild(cfg, position);
17713 // Roo.log(this.el);
17718 initEvents : function()
17720 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17721 this.el.enableDisplayMode('block');
17723 if (this.over === false) {
17726 if (this.triggers === false) {
17729 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17730 var triggers = this.trigger ? this.trigger.split(' ') : [];
17731 Roo.each(triggers, function(trigger) {
17733 if (trigger == 'click') {
17734 on_el.on('click', this.toggle, this);
17735 } else if (trigger != 'manual') {
17736 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17737 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17739 on_el.on(eventIn ,this.enter, this);
17740 on_el.on(eventOut, this.leave, this);
17751 toggle : function () {
17752 this.hoverState == 'in' ? this.leave() : this.enter();
17755 enter : function () {
17757 clearTimeout(this.timeout);
17759 this.hoverState = 'in';
17761 if (!this.delay || !this.delay.show) {
17766 this.timeout = setTimeout(function () {
17767 if (_t.hoverState == 'in') {
17770 }, this.delay.show)
17773 leave : function() {
17774 clearTimeout(this.timeout);
17776 this.hoverState = 'out';
17778 if (!this.delay || !this.delay.hide) {
17783 this.timeout = setTimeout(function () {
17784 if (_t.hoverState == 'out') {
17787 }, this.delay.hide)
17790 show : function (on_el)
17793 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17797 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17798 if (this.html !== false) {
17799 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17801 this.el.removeClass([
17802 'fade','top','bottom', 'left', 'right','in',
17803 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17805 if (!this.title.length) {
17806 this.el.select('.popover-title',true).hide();
17809 var placement = typeof this.placement == 'function' ?
17810 this.placement.call(this, this.el, on_el) :
17813 var autoToken = /\s?auto?\s?/i;
17814 var autoPlace = autoToken.test(placement);
17816 placement = placement.replace(autoToken, '') || 'top';
17820 //this.el.setXY([0,0]);
17822 this.el.dom.style.display='block';
17823 this.el.addClass(placement);
17825 //this.el.appendTo(on_el);
17827 var p = this.getPosition();
17828 var box = this.el.getBox();
17833 var align = Roo.bootstrap.Popover.alignment[placement];
17836 this.el.alignTo(on_el, align[0],align[1]);
17837 //var arrow = this.el.select('.arrow',true).first();
17838 //arrow.set(align[2],
17840 this.el.addClass('in');
17843 if (this.el.hasClass('fade')) {
17847 this.hoverState = 'in';
17849 this.fireEvent('show', this);
17854 this.el.setXY([0,0]);
17855 this.el.removeClass('in');
17857 this.hoverState = null;
17859 this.fireEvent('hide', this);
17864 Roo.bootstrap.Popover.alignment = {
17865 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17866 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17867 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17868 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17879 * @class Roo.bootstrap.Progress
17880 * @extends Roo.bootstrap.Component
17881 * Bootstrap Progress class
17882 * @cfg {Boolean} striped striped of the progress bar
17883 * @cfg {Boolean} active animated of the progress bar
17887 * Create a new Progress
17888 * @param {Object} config The config object
17891 Roo.bootstrap.Progress = function(config){
17892 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17895 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17900 getAutoCreate : function(){
17908 cfg.cls += ' progress-striped';
17912 cfg.cls += ' active';
17931 * @class Roo.bootstrap.ProgressBar
17932 * @extends Roo.bootstrap.Component
17933 * Bootstrap ProgressBar class
17934 * @cfg {Number} aria_valuenow aria-value now
17935 * @cfg {Number} aria_valuemin aria-value min
17936 * @cfg {Number} aria_valuemax aria-value max
17937 * @cfg {String} label label for the progress bar
17938 * @cfg {String} panel (success | info | warning | danger )
17939 * @cfg {String} role role of the progress bar
17940 * @cfg {String} sr_only text
17944 * Create a new ProgressBar
17945 * @param {Object} config The config object
17948 Roo.bootstrap.ProgressBar = function(config){
17949 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17952 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17956 aria_valuemax : 100,
17962 getAutoCreate : function()
17967 cls: 'progress-bar',
17968 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17980 cfg.role = this.role;
17983 if(this.aria_valuenow){
17984 cfg['aria-valuenow'] = this.aria_valuenow;
17987 if(this.aria_valuemin){
17988 cfg['aria-valuemin'] = this.aria_valuemin;
17991 if(this.aria_valuemax){
17992 cfg['aria-valuemax'] = this.aria_valuemax;
17995 if(this.label && !this.sr_only){
17996 cfg.html = this.label;
18000 cfg.cls += ' progress-bar-' + this.panel;
18006 update : function(aria_valuenow)
18008 this.aria_valuenow = aria_valuenow;
18010 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18025 * @class Roo.bootstrap.TabGroup
18026 * @extends Roo.bootstrap.Column
18027 * Bootstrap Column class
18028 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18029 * @cfg {Boolean} carousel true to make the group behave like a carousel
18030 * @cfg {Boolean} bullets show bullets for the panels
18031 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18032 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18033 * @cfg {Boolean} showarrow (true|false) show arrow default true
18036 * Create a new TabGroup
18037 * @param {Object} config The config object
18040 Roo.bootstrap.TabGroup = function(config){
18041 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18043 this.navId = Roo.id();
18046 Roo.bootstrap.TabGroup.register(this);
18050 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18053 transition : false,
18058 slideOnTouch : false,
18061 getAutoCreate : function()
18063 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18065 cfg.cls += ' tab-content';
18067 if (this.carousel) {
18068 cfg.cls += ' carousel slide';
18071 cls : 'carousel-inner',
18075 if(this.bullets && !Roo.isTouch){
18078 cls : 'carousel-bullets',
18082 if(this.bullets_cls){
18083 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18090 cfg.cn[0].cn.push(bullets);
18093 if(this.showarrow){
18094 cfg.cn[0].cn.push({
18096 class : 'carousel-arrow',
18100 class : 'carousel-prev',
18104 class : 'fa fa-chevron-left'
18110 class : 'carousel-next',
18114 class : 'fa fa-chevron-right'
18127 initEvents: function()
18129 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18130 // this.el.on("touchstart", this.onTouchStart, this);
18133 if(this.autoslide){
18136 this.slideFn = window.setInterval(function() {
18137 _this.showPanelNext();
18141 if(this.showarrow){
18142 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18143 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18149 // onTouchStart : function(e, el, o)
18151 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18155 // this.showPanelNext();
18159 getChildContainer : function()
18161 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18165 * register a Navigation item
18166 * @param {Roo.bootstrap.NavItem} the navitem to add
18168 register : function(item)
18170 this.tabs.push( item);
18171 item.navId = this.navId; // not really needed..
18176 getActivePanel : function()
18179 Roo.each(this.tabs, function(t) {
18189 getPanelByName : function(n)
18192 Roo.each(this.tabs, function(t) {
18193 if (t.tabId == n) {
18201 indexOfPanel : function(p)
18204 Roo.each(this.tabs, function(t,i) {
18205 if (t.tabId == p.tabId) {
18214 * show a specific panel
18215 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18216 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18218 showPanel : function (pan)
18220 if(this.transition || typeof(pan) == 'undefined'){
18221 Roo.log("waiting for the transitionend");
18225 if (typeof(pan) == 'number') {
18226 pan = this.tabs[pan];
18229 if (typeof(pan) == 'string') {
18230 pan = this.getPanelByName(pan);
18233 var cur = this.getActivePanel();
18236 Roo.log('pan or acitve pan is undefined');
18240 if (pan.tabId == this.getActivePanel().tabId) {
18244 if (false === cur.fireEvent('beforedeactivate')) {
18248 if(this.bullets > 0 && !Roo.isTouch){
18249 this.setActiveBullet(this.indexOfPanel(pan));
18252 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18254 this.transition = true;
18255 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18256 var lr = dir == 'next' ? 'left' : 'right';
18257 pan.el.addClass(dir); // or prev
18258 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18259 cur.el.addClass(lr); // or right
18260 pan.el.addClass(lr);
18263 cur.el.on('transitionend', function() {
18264 Roo.log("trans end?");
18266 pan.el.removeClass([lr,dir]);
18267 pan.setActive(true);
18269 cur.el.removeClass([lr]);
18270 cur.setActive(false);
18272 _this.transition = false;
18274 }, this, { single: true } );
18279 cur.setActive(false);
18280 pan.setActive(true);
18285 showPanelNext : function()
18287 var i = this.indexOfPanel(this.getActivePanel());
18289 if (i >= this.tabs.length - 1 && !this.autoslide) {
18293 if (i >= this.tabs.length - 1 && this.autoslide) {
18297 this.showPanel(this.tabs[i+1]);
18300 showPanelPrev : function()
18302 var i = this.indexOfPanel(this.getActivePanel());
18304 if (i < 1 && !this.autoslide) {
18308 if (i < 1 && this.autoslide) {
18309 i = this.tabs.length;
18312 this.showPanel(this.tabs[i-1]);
18316 addBullet: function()
18318 if(!this.bullets || Roo.isTouch){
18321 var ctr = this.el.select('.carousel-bullets',true).first();
18322 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18323 var bullet = ctr.createChild({
18324 cls : 'bullet bullet-' + i
18325 },ctr.dom.lastChild);
18330 bullet.on('click', (function(e, el, o, ii, t){
18332 e.preventDefault();
18334 this.showPanel(ii);
18336 if(this.autoslide && this.slideFn){
18337 clearInterval(this.slideFn);
18338 this.slideFn = window.setInterval(function() {
18339 _this.showPanelNext();
18343 }).createDelegate(this, [i, bullet], true));
18348 setActiveBullet : function(i)
18354 Roo.each(this.el.select('.bullet', true).elements, function(el){
18355 el.removeClass('selected');
18358 var bullet = this.el.select('.bullet-' + i, true).first();
18364 bullet.addClass('selected');
18375 Roo.apply(Roo.bootstrap.TabGroup, {
18379 * register a Navigation Group
18380 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18382 register : function(navgrp)
18384 this.groups[navgrp.navId] = navgrp;
18388 * fetch a Navigation Group based on the navigation ID
18389 * if one does not exist , it will get created.
18390 * @param {string} the navgroup to add
18391 * @returns {Roo.bootstrap.NavGroup} the navgroup
18393 get: function(navId) {
18394 if (typeof(this.groups[navId]) == 'undefined') {
18395 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18397 return this.groups[navId] ;
18412 * @class Roo.bootstrap.TabPanel
18413 * @extends Roo.bootstrap.Component
18414 * Bootstrap TabPanel class
18415 * @cfg {Boolean} active panel active
18416 * @cfg {String} html panel content
18417 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18418 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18419 * @cfg {String} href click to link..
18423 * Create a new TabPanel
18424 * @param {Object} config The config object
18427 Roo.bootstrap.TabPanel = function(config){
18428 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18432 * Fires when the active status changes
18433 * @param {Roo.bootstrap.TabPanel} this
18434 * @param {Boolean} state the new state
18439 * @event beforedeactivate
18440 * Fires before a tab is de-activated - can be used to do validation on a form.
18441 * @param {Roo.bootstrap.TabPanel} this
18442 * @return {Boolean} false if there is an error
18445 'beforedeactivate': true
18448 this.tabId = this.tabId || Roo.id();
18452 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18460 getAutoCreate : function(){
18463 // item is needed for carousel - not sure if it has any effect otherwise
18464 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18465 html: this.html || ''
18469 cfg.cls += ' active';
18473 cfg.tabId = this.tabId;
18480 initEvents: function()
18482 var p = this.parent();
18484 this.navId = this.navId || p.navId;
18486 if (typeof(this.navId) != 'undefined') {
18487 // not really needed.. but just in case.. parent should be a NavGroup.
18488 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18492 var i = tg.tabs.length - 1;
18494 if(this.active && tg.bullets > 0 && i < tg.bullets){
18495 tg.setActiveBullet(i);
18499 this.el.on('click', this.onClick, this);
18502 this.el.on("touchstart", this.onTouchStart, this);
18503 this.el.on("touchmove", this.onTouchMove, this);
18504 this.el.on("touchend", this.onTouchEnd, this);
18509 onRender : function(ct, position)
18511 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18514 setActive : function(state)
18516 Roo.log("panel - set active " + this.tabId + "=" + state);
18518 this.active = state;
18520 this.el.removeClass('active');
18522 } else if (!this.el.hasClass('active')) {
18523 this.el.addClass('active');
18526 this.fireEvent('changed', this, state);
18529 onClick : function(e)
18531 e.preventDefault();
18533 if(!this.href.length){
18537 window.location.href = this.href;
18546 onTouchStart : function(e)
18548 this.swiping = false;
18550 this.startX = e.browserEvent.touches[0].clientX;
18551 this.startY = e.browserEvent.touches[0].clientY;
18554 onTouchMove : function(e)
18556 this.swiping = true;
18558 this.endX = e.browserEvent.touches[0].clientX;
18559 this.endY = e.browserEvent.touches[0].clientY;
18562 onTouchEnd : function(e)
18569 var tabGroup = this.parent();
18571 if(this.endX > this.startX){ // swiping right
18572 tabGroup.showPanelPrev();
18576 if(this.startX > this.endX){ // swiping left
18577 tabGroup.showPanelNext();
18596 * @class Roo.bootstrap.DateField
18597 * @extends Roo.bootstrap.Input
18598 * Bootstrap DateField class
18599 * @cfg {Number} weekStart default 0
18600 * @cfg {String} viewMode default empty, (months|years)
18601 * @cfg {String} minViewMode default empty, (months|years)
18602 * @cfg {Number} startDate default -Infinity
18603 * @cfg {Number} endDate default Infinity
18604 * @cfg {Boolean} todayHighlight default false
18605 * @cfg {Boolean} todayBtn default false
18606 * @cfg {Boolean} calendarWeeks default false
18607 * @cfg {Object} daysOfWeekDisabled default empty
18608 * @cfg {Boolean} singleMode default false (true | false)
18610 * @cfg {Boolean} keyboardNavigation default true
18611 * @cfg {String} language default en
18614 * Create a new DateField
18615 * @param {Object} config The config object
18618 Roo.bootstrap.DateField = function(config){
18619 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18623 * Fires when this field show.
18624 * @param {Roo.bootstrap.DateField} this
18625 * @param {Mixed} date The date value
18630 * Fires when this field hide.
18631 * @param {Roo.bootstrap.DateField} this
18632 * @param {Mixed} date The date value
18637 * Fires when select a date.
18638 * @param {Roo.bootstrap.DateField} this
18639 * @param {Mixed} date The date value
18643 * @event beforeselect
18644 * Fires when before select a date.
18645 * @param {Roo.bootstrap.DateField} this
18646 * @param {Mixed} date The date value
18648 beforeselect : true
18652 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18655 * @cfg {String} format
18656 * The default date format string which can be overriden for localization support. The format must be
18657 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18661 * @cfg {String} altFormats
18662 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18663 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18665 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18673 todayHighlight : false,
18679 keyboardNavigation: true,
18681 calendarWeeks: false,
18683 startDate: -Infinity,
18687 daysOfWeekDisabled: [],
18691 singleMode : false,
18693 UTCDate: function()
18695 return new Date(Date.UTC.apply(Date, arguments));
18698 UTCToday: function()
18700 var today = new Date();
18701 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18704 getDate: function() {
18705 var d = this.getUTCDate();
18706 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18709 getUTCDate: function() {
18713 setDate: function(d) {
18714 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18717 setUTCDate: function(d) {
18719 this.setValue(this.formatDate(this.date));
18722 onRender: function(ct, position)
18725 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18727 this.language = this.language || 'en';
18728 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18729 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18731 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18732 this.format = this.format || 'm/d/y';
18733 this.isInline = false;
18734 this.isInput = true;
18735 this.component = this.el.select('.add-on', true).first() || false;
18736 this.component = (this.component && this.component.length === 0) ? false : this.component;
18737 this.hasInput = this.component && this.inputEl().length;
18739 if (typeof(this.minViewMode === 'string')) {
18740 switch (this.minViewMode) {
18742 this.minViewMode = 1;
18745 this.minViewMode = 2;
18748 this.minViewMode = 0;
18753 if (typeof(this.viewMode === 'string')) {
18754 switch (this.viewMode) {
18767 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18769 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18771 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18773 this.picker().on('mousedown', this.onMousedown, this);
18774 this.picker().on('click', this.onClick, this);
18776 this.picker().addClass('datepicker-dropdown');
18778 this.startViewMode = this.viewMode;
18780 if(this.singleMode){
18781 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18782 v.setVisibilityMode(Roo.Element.DISPLAY);
18786 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18787 v.setStyle('width', '189px');
18791 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18792 if(!this.calendarWeeks){
18797 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18798 v.attr('colspan', function(i, val){
18799 return parseInt(val) + 1;
18804 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18806 this.setStartDate(this.startDate);
18807 this.setEndDate(this.endDate);
18809 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18816 if(this.isInline) {
18821 picker : function()
18823 return this.pickerEl;
18824 // return this.el.select('.datepicker', true).first();
18827 fillDow: function()
18829 var dowCnt = this.weekStart;
18838 if(this.calendarWeeks){
18846 while (dowCnt < this.weekStart + 7) {
18850 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18854 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18857 fillMonths: function()
18860 var months = this.picker().select('>.datepicker-months td', true).first();
18862 months.dom.innerHTML = '';
18868 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18871 months.createChild(month);
18878 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;
18880 if (this.date < this.startDate) {
18881 this.viewDate = new Date(this.startDate);
18882 } else if (this.date > this.endDate) {
18883 this.viewDate = new Date(this.endDate);
18885 this.viewDate = new Date(this.date);
18893 var d = new Date(this.viewDate),
18894 year = d.getUTCFullYear(),
18895 month = d.getUTCMonth(),
18896 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18897 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18898 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18899 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18900 currentDate = this.date && this.date.valueOf(),
18901 today = this.UTCToday();
18903 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18905 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18907 // this.picker.select('>tfoot th.today').
18908 // .text(dates[this.language].today)
18909 // .toggle(this.todayBtn !== false);
18911 this.updateNavArrows();
18914 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18916 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18918 prevMonth.setUTCDate(day);
18920 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18922 var nextMonth = new Date(prevMonth);
18924 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18926 nextMonth = nextMonth.valueOf();
18928 var fillMonths = false;
18930 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18932 while(prevMonth.valueOf() <= nextMonth) {
18935 if (prevMonth.getUTCDay() === this.weekStart) {
18937 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18945 if(this.calendarWeeks){
18946 // ISO 8601: First week contains first thursday.
18947 // ISO also states week starts on Monday, but we can be more abstract here.
18949 // Start of current week: based on weekstart/current date
18950 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18951 // Thursday of this week
18952 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18953 // First Thursday of year, year from thursday
18954 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18955 // Calendar week: ms between thursdays, div ms per day, div 7 days
18956 calWeek = (th - yth) / 864e5 / 7 + 1;
18958 fillMonths.cn.push({
18966 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18968 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18971 if (this.todayHighlight &&
18972 prevMonth.getUTCFullYear() == today.getFullYear() &&
18973 prevMonth.getUTCMonth() == today.getMonth() &&
18974 prevMonth.getUTCDate() == today.getDate()) {
18975 clsName += ' today';
18978 if (currentDate && prevMonth.valueOf() === currentDate) {
18979 clsName += ' active';
18982 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18983 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18984 clsName += ' disabled';
18987 fillMonths.cn.push({
18989 cls: 'day ' + clsName,
18990 html: prevMonth.getDate()
18993 prevMonth.setDate(prevMonth.getDate()+1);
18996 var currentYear = this.date && this.date.getUTCFullYear();
18997 var currentMonth = this.date && this.date.getUTCMonth();
18999 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19001 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19002 v.removeClass('active');
19004 if(currentYear === year && k === currentMonth){
19005 v.addClass('active');
19008 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19009 v.addClass('disabled');
19015 year = parseInt(year/10, 10) * 10;
19017 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19019 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19022 for (var i = -1; i < 11; i++) {
19023 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19025 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19033 showMode: function(dir)
19036 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19039 Roo.each(this.picker().select('>div',true).elements, function(v){
19040 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19043 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19048 if(this.isInline) {
19052 this.picker().removeClass(['bottom', 'top']);
19054 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19056 * place to the top of element!
19060 this.picker().addClass('top');
19061 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19066 this.picker().addClass('bottom');
19068 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19071 parseDate : function(value)
19073 if(!value || value instanceof Date){
19076 var v = Date.parseDate(value, this.format);
19077 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19078 v = Date.parseDate(value, 'Y-m-d');
19080 if(!v && this.altFormats){
19081 if(!this.altFormatsArray){
19082 this.altFormatsArray = this.altFormats.split("|");
19084 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19085 v = Date.parseDate(value, this.altFormatsArray[i]);
19091 formatDate : function(date, fmt)
19093 return (!date || !(date instanceof Date)) ?
19094 date : date.dateFormat(fmt || this.format);
19097 onFocus : function()
19099 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19103 onBlur : function()
19105 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19107 var d = this.inputEl().getValue();
19114 showPopup : function()
19116 this.picker().show();
19120 this.fireEvent('showpopup', this, this.date);
19123 hidePopup : function()
19125 if(this.isInline) {
19128 this.picker().hide();
19129 this.viewMode = this.startViewMode;
19132 this.fireEvent('hidepopup', this, this.date);
19136 onMousedown: function(e)
19138 e.stopPropagation();
19139 e.preventDefault();
19144 Roo.bootstrap.DateField.superclass.keyup.call(this);
19148 setValue: function(v)
19150 if(this.fireEvent('beforeselect', this, v) !== false){
19151 var d = new Date(this.parseDate(v) ).clearTime();
19153 if(isNaN(d.getTime())){
19154 this.date = this.viewDate = '';
19155 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19159 v = this.formatDate(d);
19161 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19163 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19167 this.fireEvent('select', this, this.date);
19171 getValue: function()
19173 return this.formatDate(this.date);
19176 fireKey: function(e)
19178 if (!this.picker().isVisible()){
19179 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19185 var dateChanged = false,
19187 newDate, newViewDate;
19192 e.preventDefault();
19196 if (!this.keyboardNavigation) {
19199 dir = e.keyCode == 37 ? -1 : 1;
19202 newDate = this.moveYear(this.date, dir);
19203 newViewDate = this.moveYear(this.viewDate, dir);
19204 } else if (e.shiftKey){
19205 newDate = this.moveMonth(this.date, dir);
19206 newViewDate = this.moveMonth(this.viewDate, dir);
19208 newDate = new Date(this.date);
19209 newDate.setUTCDate(this.date.getUTCDate() + dir);
19210 newViewDate = new Date(this.viewDate);
19211 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19213 if (this.dateWithinRange(newDate)){
19214 this.date = newDate;
19215 this.viewDate = newViewDate;
19216 this.setValue(this.formatDate(this.date));
19218 e.preventDefault();
19219 dateChanged = true;
19224 if (!this.keyboardNavigation) {
19227 dir = e.keyCode == 38 ? -1 : 1;
19229 newDate = this.moveYear(this.date, dir);
19230 newViewDate = this.moveYear(this.viewDate, dir);
19231 } else if (e.shiftKey){
19232 newDate = this.moveMonth(this.date, dir);
19233 newViewDate = this.moveMonth(this.viewDate, dir);
19235 newDate = new Date(this.date);
19236 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19237 newViewDate = new Date(this.viewDate);
19238 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19240 if (this.dateWithinRange(newDate)){
19241 this.date = newDate;
19242 this.viewDate = newViewDate;
19243 this.setValue(this.formatDate(this.date));
19245 e.preventDefault();
19246 dateChanged = true;
19250 this.setValue(this.formatDate(this.date));
19252 e.preventDefault();
19255 this.setValue(this.formatDate(this.date));
19269 onClick: function(e)
19271 e.stopPropagation();
19272 e.preventDefault();
19274 var target = e.getTarget();
19276 if(target.nodeName.toLowerCase() === 'i'){
19277 target = Roo.get(target).dom.parentNode;
19280 var nodeName = target.nodeName;
19281 var className = target.className;
19282 var html = target.innerHTML;
19283 //Roo.log(nodeName);
19285 switch(nodeName.toLowerCase()) {
19287 switch(className) {
19293 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19294 switch(this.viewMode){
19296 this.viewDate = this.moveMonth(this.viewDate, dir);
19300 this.viewDate = this.moveYear(this.viewDate, dir);
19306 var date = new Date();
19307 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19309 this.setValue(this.formatDate(this.date));
19316 if (className.indexOf('disabled') < 0) {
19317 this.viewDate.setUTCDate(1);
19318 if (className.indexOf('month') > -1) {
19319 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19321 var year = parseInt(html, 10) || 0;
19322 this.viewDate.setUTCFullYear(year);
19326 if(this.singleMode){
19327 this.setValue(this.formatDate(this.viewDate));
19338 //Roo.log(className);
19339 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19340 var day = parseInt(html, 10) || 1;
19341 var year = this.viewDate.getUTCFullYear(),
19342 month = this.viewDate.getUTCMonth();
19344 if (className.indexOf('old') > -1) {
19351 } else if (className.indexOf('new') > -1) {
19359 //Roo.log([year,month,day]);
19360 this.date = this.UTCDate(year, month, day,0,0,0,0);
19361 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19363 //Roo.log(this.formatDate(this.date));
19364 this.setValue(this.formatDate(this.date));
19371 setStartDate: function(startDate)
19373 this.startDate = startDate || -Infinity;
19374 if (this.startDate !== -Infinity) {
19375 this.startDate = this.parseDate(this.startDate);
19378 this.updateNavArrows();
19381 setEndDate: function(endDate)
19383 this.endDate = endDate || Infinity;
19384 if (this.endDate !== Infinity) {
19385 this.endDate = this.parseDate(this.endDate);
19388 this.updateNavArrows();
19391 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19393 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19394 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19395 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19397 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19398 return parseInt(d, 10);
19401 this.updateNavArrows();
19404 updateNavArrows: function()
19406 if(this.singleMode){
19410 var d = new Date(this.viewDate),
19411 year = d.getUTCFullYear(),
19412 month = d.getUTCMonth();
19414 Roo.each(this.picker().select('.prev', true).elements, function(v){
19416 switch (this.viewMode) {
19419 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19425 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19432 Roo.each(this.picker().select('.next', true).elements, function(v){
19434 switch (this.viewMode) {
19437 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19443 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19451 moveMonth: function(date, dir)
19456 var new_date = new Date(date.valueOf()),
19457 day = new_date.getUTCDate(),
19458 month = new_date.getUTCMonth(),
19459 mag = Math.abs(dir),
19461 dir = dir > 0 ? 1 : -1;
19464 // If going back one month, make sure month is not current month
19465 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19467 return new_date.getUTCMonth() == month;
19469 // If going forward one month, make sure month is as expected
19470 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19472 return new_date.getUTCMonth() != new_month;
19474 new_month = month + dir;
19475 new_date.setUTCMonth(new_month);
19476 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19477 if (new_month < 0 || new_month > 11) {
19478 new_month = (new_month + 12) % 12;
19481 // For magnitudes >1, move one month at a time...
19482 for (var i=0; i<mag; i++) {
19483 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19484 new_date = this.moveMonth(new_date, dir);
19486 // ...then reset the day, keeping it in the new month
19487 new_month = new_date.getUTCMonth();
19488 new_date.setUTCDate(day);
19490 return new_month != new_date.getUTCMonth();
19493 // Common date-resetting loop -- if date is beyond end of month, make it
19496 new_date.setUTCDate(--day);
19497 new_date.setUTCMonth(new_month);
19502 moveYear: function(date, dir)
19504 return this.moveMonth(date, dir*12);
19507 dateWithinRange: function(date)
19509 return date >= this.startDate && date <= this.endDate;
19515 this.picker().remove();
19518 validateValue : function(value)
19520 if(this.getVisibilityEl().hasClass('hidden')){
19524 if(value.length < 1) {
19525 if(this.allowBlank){
19531 if(value.length < this.minLength){
19534 if(value.length > this.maxLength){
19538 var vt = Roo.form.VTypes;
19539 if(!vt[this.vtype](value, this)){
19543 if(typeof this.validator == "function"){
19544 var msg = this.validator(value);
19550 if(this.regex && !this.regex.test(value)){
19554 if(typeof(this.parseDate(value)) == 'undefined'){
19558 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19562 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19572 this.date = this.viewDate = '';
19574 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19579 Roo.apply(Roo.bootstrap.DateField, {
19590 html: '<i class="fa fa-arrow-left"/>'
19600 html: '<i class="fa fa-arrow-right"/>'
19642 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19643 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19644 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19645 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19646 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19659 navFnc: 'FullYear',
19664 navFnc: 'FullYear',
19669 Roo.apply(Roo.bootstrap.DateField, {
19673 cls: 'datepicker dropdown-menu roo-dynamic',
19677 cls: 'datepicker-days',
19681 cls: 'table-condensed',
19683 Roo.bootstrap.DateField.head,
19687 Roo.bootstrap.DateField.footer
19694 cls: 'datepicker-months',
19698 cls: 'table-condensed',
19700 Roo.bootstrap.DateField.head,
19701 Roo.bootstrap.DateField.content,
19702 Roo.bootstrap.DateField.footer
19709 cls: 'datepicker-years',
19713 cls: 'table-condensed',
19715 Roo.bootstrap.DateField.head,
19716 Roo.bootstrap.DateField.content,
19717 Roo.bootstrap.DateField.footer
19736 * @class Roo.bootstrap.TimeField
19737 * @extends Roo.bootstrap.Input
19738 * Bootstrap DateField class
19742 * Create a new TimeField
19743 * @param {Object} config The config object
19746 Roo.bootstrap.TimeField = function(config){
19747 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19751 * Fires when this field show.
19752 * @param {Roo.bootstrap.DateField} thisthis
19753 * @param {Mixed} date The date value
19758 * Fires when this field hide.
19759 * @param {Roo.bootstrap.DateField} this
19760 * @param {Mixed} date The date value
19765 * Fires when select a date.
19766 * @param {Roo.bootstrap.DateField} this
19767 * @param {Mixed} date The date value
19773 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19776 * @cfg {String} format
19777 * The default time format string which can be overriden for localization support. The format must be
19778 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19782 onRender: function(ct, position)
19785 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19787 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19789 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19791 this.pop = this.picker().select('>.datepicker-time',true).first();
19792 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19794 this.picker().on('mousedown', this.onMousedown, this);
19795 this.picker().on('click', this.onClick, this);
19797 this.picker().addClass('datepicker-dropdown');
19802 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19803 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19804 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19805 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19806 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19807 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19811 fireKey: function(e){
19812 if (!this.picker().isVisible()){
19813 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19819 e.preventDefault();
19827 this.onTogglePeriod();
19830 this.onIncrementMinutes();
19833 this.onDecrementMinutes();
19842 onClick: function(e) {
19843 e.stopPropagation();
19844 e.preventDefault();
19847 picker : function()
19849 return this.el.select('.datepicker', true).first();
19852 fillTime: function()
19854 var time = this.pop.select('tbody', true).first();
19856 time.dom.innerHTML = '';
19871 cls: 'hours-up glyphicon glyphicon-chevron-up'
19891 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19912 cls: 'timepicker-hour',
19927 cls: 'timepicker-minute',
19942 cls: 'btn btn-primary period',
19964 cls: 'hours-down glyphicon glyphicon-chevron-down'
19984 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20002 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20009 var hours = this.time.getHours();
20010 var minutes = this.time.getMinutes();
20023 hours = hours - 12;
20027 hours = '0' + hours;
20031 minutes = '0' + minutes;
20034 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20035 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20036 this.pop.select('button', true).first().dom.innerHTML = period;
20042 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20044 var cls = ['bottom'];
20046 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20053 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20058 this.picker().addClass(cls.join('-'));
20062 Roo.each(cls, function(c){
20064 _this.picker().setTop(_this.inputEl().getHeight());
20068 _this.picker().setTop(0 - _this.picker().getHeight());
20073 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20077 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20084 onFocus : function()
20086 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20090 onBlur : function()
20092 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20098 this.picker().show();
20103 this.fireEvent('show', this, this.date);
20108 this.picker().hide();
20111 this.fireEvent('hide', this, this.date);
20114 setTime : function()
20117 this.setValue(this.time.format(this.format));
20119 this.fireEvent('select', this, this.date);
20124 onMousedown: function(e){
20125 e.stopPropagation();
20126 e.preventDefault();
20129 onIncrementHours: function()
20131 Roo.log('onIncrementHours');
20132 this.time = this.time.add(Date.HOUR, 1);
20137 onDecrementHours: function()
20139 Roo.log('onDecrementHours');
20140 this.time = this.time.add(Date.HOUR, -1);
20144 onIncrementMinutes: function()
20146 Roo.log('onIncrementMinutes');
20147 this.time = this.time.add(Date.MINUTE, 1);
20151 onDecrementMinutes: function()
20153 Roo.log('onDecrementMinutes');
20154 this.time = this.time.add(Date.MINUTE, -1);
20158 onTogglePeriod: function()
20160 Roo.log('onTogglePeriod');
20161 this.time = this.time.add(Date.HOUR, 12);
20168 Roo.apply(Roo.bootstrap.TimeField, {
20198 cls: 'btn btn-info ok',
20210 Roo.apply(Roo.bootstrap.TimeField, {
20214 cls: 'datepicker dropdown-menu',
20218 cls: 'datepicker-time',
20222 cls: 'table-condensed',
20224 Roo.bootstrap.TimeField.content,
20225 Roo.bootstrap.TimeField.footer
20244 * @class Roo.bootstrap.MonthField
20245 * @extends Roo.bootstrap.Input
20246 * Bootstrap MonthField class
20248 * @cfg {String} language default en
20251 * Create a new MonthField
20252 * @param {Object} config The config object
20255 Roo.bootstrap.MonthField = function(config){
20256 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20261 * Fires when this field show.
20262 * @param {Roo.bootstrap.MonthField} this
20263 * @param {Mixed} date The date value
20268 * Fires when this field hide.
20269 * @param {Roo.bootstrap.MonthField} this
20270 * @param {Mixed} date The date value
20275 * Fires when select a date.
20276 * @param {Roo.bootstrap.MonthField} this
20277 * @param {String} oldvalue The old value
20278 * @param {String} newvalue The new value
20284 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20286 onRender: function(ct, position)
20289 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20291 this.language = this.language || 'en';
20292 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20293 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20295 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20296 this.isInline = false;
20297 this.isInput = true;
20298 this.component = this.el.select('.add-on', true).first() || false;
20299 this.component = (this.component && this.component.length === 0) ? false : this.component;
20300 this.hasInput = this.component && this.inputEL().length;
20302 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20304 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20306 this.picker().on('mousedown', this.onMousedown, this);
20307 this.picker().on('click', this.onClick, this);
20309 this.picker().addClass('datepicker-dropdown');
20311 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20312 v.setStyle('width', '189px');
20319 if(this.isInline) {
20325 setValue: function(v, suppressEvent)
20327 var o = this.getValue();
20329 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20333 if(suppressEvent !== true){
20334 this.fireEvent('select', this, o, v);
20339 getValue: function()
20344 onClick: function(e)
20346 e.stopPropagation();
20347 e.preventDefault();
20349 var target = e.getTarget();
20351 if(target.nodeName.toLowerCase() === 'i'){
20352 target = Roo.get(target).dom.parentNode;
20355 var nodeName = target.nodeName;
20356 var className = target.className;
20357 var html = target.innerHTML;
20359 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20363 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20365 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20371 picker : function()
20373 return this.pickerEl;
20376 fillMonths: function()
20379 var months = this.picker().select('>.datepicker-months td', true).first();
20381 months.dom.innerHTML = '';
20387 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20390 months.createChild(month);
20399 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20400 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20403 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20404 e.removeClass('active');
20406 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20407 e.addClass('active');
20414 if(this.isInline) {
20418 this.picker().removeClass(['bottom', 'top']);
20420 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20422 * place to the top of element!
20426 this.picker().addClass('top');
20427 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20432 this.picker().addClass('bottom');
20434 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20437 onFocus : function()
20439 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20443 onBlur : function()
20445 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20447 var d = this.inputEl().getValue();
20456 this.picker().show();
20457 this.picker().select('>.datepicker-months', true).first().show();
20461 this.fireEvent('show', this, this.date);
20466 if(this.isInline) {
20469 this.picker().hide();
20470 this.fireEvent('hide', this, this.date);
20474 onMousedown: function(e)
20476 e.stopPropagation();
20477 e.preventDefault();
20482 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20486 fireKey: function(e)
20488 if (!this.picker().isVisible()){
20489 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20500 e.preventDefault();
20504 dir = e.keyCode == 37 ? -1 : 1;
20506 this.vIndex = this.vIndex + dir;
20508 if(this.vIndex < 0){
20512 if(this.vIndex > 11){
20516 if(isNaN(this.vIndex)){
20520 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20526 dir = e.keyCode == 38 ? -1 : 1;
20528 this.vIndex = this.vIndex + dir * 4;
20530 if(this.vIndex < 0){
20534 if(this.vIndex > 11){
20538 if(isNaN(this.vIndex)){
20542 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20547 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20548 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20552 e.preventDefault();
20555 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20556 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20572 this.picker().remove();
20577 Roo.apply(Roo.bootstrap.MonthField, {
20596 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20597 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20602 Roo.apply(Roo.bootstrap.MonthField, {
20606 cls: 'datepicker dropdown-menu roo-dynamic',
20610 cls: 'datepicker-months',
20614 cls: 'table-condensed',
20616 Roo.bootstrap.DateField.content
20636 * @class Roo.bootstrap.CheckBox
20637 * @extends Roo.bootstrap.Input
20638 * Bootstrap CheckBox class
20640 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20641 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20642 * @cfg {String} boxLabel The text that appears beside the checkbox
20643 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20644 * @cfg {Boolean} checked initnal the element
20645 * @cfg {Boolean} inline inline the element (default false)
20646 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20647 * @cfg {String} tooltip label tooltip
20650 * Create a new CheckBox
20651 * @param {Object} config The config object
20654 Roo.bootstrap.CheckBox = function(config){
20655 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20660 * Fires when the element is checked or unchecked.
20661 * @param {Roo.bootstrap.CheckBox} this This input
20662 * @param {Boolean} checked The new checked value
20667 * Fires when the element is click.
20668 * @param {Roo.bootstrap.CheckBox} this This input
20675 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20677 inputType: 'checkbox',
20686 getAutoCreate : function()
20688 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20694 cfg.cls = 'form-group ' + this.inputType; //input-group
20697 cfg.cls += ' ' + this.inputType + '-inline';
20703 type : this.inputType,
20704 value : this.inputValue,
20705 cls : 'roo-' + this.inputType, //'form-box',
20706 placeholder : this.placeholder || ''
20710 if(this.inputType != 'radio'){
20714 cls : 'roo-hidden-value',
20715 value : this.checked ? this.inputValue : this.valueOff
20720 if (this.weight) { // Validity check?
20721 cfg.cls += " " + this.inputType + "-" + this.weight;
20724 if (this.disabled) {
20725 input.disabled=true;
20729 input.checked = this.checked;
20734 input.name = this.name;
20736 if(this.inputType != 'radio'){
20737 hidden.name = this.name;
20738 input.name = '_hidden_' + this.name;
20743 input.cls += ' input-' + this.size;
20748 ['xs','sm','md','lg'].map(function(size){
20749 if (settings[size]) {
20750 cfg.cls += ' col-' + size + '-' + settings[size];
20754 var inputblock = input;
20756 if (this.before || this.after) {
20759 cls : 'input-group',
20764 inputblock.cn.push({
20766 cls : 'input-group-addon',
20771 inputblock.cn.push(input);
20773 if(this.inputType != 'radio'){
20774 inputblock.cn.push(hidden);
20778 inputblock.cn.push({
20780 cls : 'input-group-addon',
20787 if (align ==='left' && this.fieldLabel.length) {
20788 // Roo.log("left and has label");
20793 cls : 'control-label',
20794 html : this.fieldLabel
20804 if(this.labelWidth > 12){
20805 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20808 if(this.labelWidth < 13 && this.labelmd == 0){
20809 this.labelmd = this.labelWidth;
20812 if(this.labellg > 0){
20813 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20814 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20817 if(this.labelmd > 0){
20818 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20819 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20822 if(this.labelsm > 0){
20823 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20824 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20827 if(this.labelxs > 0){
20828 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20829 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20832 } else if ( this.fieldLabel.length) {
20833 // Roo.log(" label");
20837 tag: this.boxLabel ? 'span' : 'label',
20839 cls: 'control-label box-input-label',
20840 //cls : 'input-group-addon',
20841 html : this.fieldLabel
20850 // Roo.log(" no label && no align");
20851 cfg.cn = [ inputblock ] ;
20857 var boxLabelCfg = {
20859 //'for': id, // box label is handled by onclick - so no for...
20861 html: this.boxLabel
20865 boxLabelCfg.tooltip = this.tooltip;
20868 cfg.cn.push(boxLabelCfg);
20871 if(this.inputType != 'radio'){
20872 cfg.cn.push(hidden);
20880 * return the real input element.
20882 inputEl: function ()
20884 return this.el.select('input.roo-' + this.inputType,true).first();
20886 hiddenEl: function ()
20888 return this.el.select('input.roo-hidden-value',true).first();
20891 labelEl: function()
20893 return this.el.select('label.control-label',true).first();
20895 /* depricated... */
20899 return this.labelEl();
20902 boxLabelEl: function()
20904 return this.el.select('label.box-label',true).first();
20907 initEvents : function()
20909 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20911 this.inputEl().on('click', this.onClick, this);
20913 if (this.boxLabel) {
20914 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20917 this.startValue = this.getValue();
20920 Roo.bootstrap.CheckBox.register(this);
20924 onClick : function(e)
20926 if(this.fireEvent('click', this, e) !== false){
20927 this.setChecked(!this.checked);
20932 setChecked : function(state,suppressEvent)
20934 this.startValue = this.getValue();
20936 if(this.inputType == 'radio'){
20938 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20939 e.dom.checked = false;
20942 this.inputEl().dom.checked = true;
20944 this.inputEl().dom.value = this.inputValue;
20946 if(suppressEvent !== true){
20947 this.fireEvent('check', this, true);
20955 this.checked = state;
20957 this.inputEl().dom.checked = state;
20960 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20962 if(suppressEvent !== true){
20963 this.fireEvent('check', this, state);
20969 getValue : function()
20971 if(this.inputType == 'radio'){
20972 return this.getGroupValue();
20975 return this.hiddenEl().dom.value;
20979 getGroupValue : function()
20981 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20985 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20988 setValue : function(v,suppressEvent)
20990 if(this.inputType == 'radio'){
20991 this.setGroupValue(v, suppressEvent);
20995 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21000 setGroupValue : function(v, suppressEvent)
21002 this.startValue = this.getValue();
21004 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21005 e.dom.checked = false;
21007 if(e.dom.value == v){
21008 e.dom.checked = true;
21012 if(suppressEvent !== true){
21013 this.fireEvent('check', this, true);
21021 validate : function()
21023 if(this.getVisibilityEl().hasClass('hidden')){
21029 (this.inputType == 'radio' && this.validateRadio()) ||
21030 (this.inputType == 'checkbox' && this.validateCheckbox())
21036 this.markInvalid();
21040 validateRadio : function()
21042 if(this.getVisibilityEl().hasClass('hidden')){
21046 if(this.allowBlank){
21052 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21053 if(!e.dom.checked){
21065 validateCheckbox : function()
21068 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21069 //return (this.getValue() == this.inputValue) ? true : false;
21072 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21080 for(var i in group){
21081 if(group[i].el.isVisible(true)){
21089 for(var i in group){
21094 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21101 * Mark this field as valid
21103 markValid : function()
21107 this.fireEvent('valid', this);
21109 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21112 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21119 if(this.inputType == 'radio'){
21120 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21121 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21122 e.findParent('.form-group', false, true).addClass(_this.validClass);
21129 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21130 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21134 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21140 for(var i in group){
21141 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21142 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21147 * Mark this field as invalid
21148 * @param {String} msg The validation message
21150 markInvalid : function(msg)
21152 if(this.allowBlank){
21158 this.fireEvent('invalid', this, msg);
21160 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21163 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21167 label.markInvalid();
21170 if(this.inputType == 'radio'){
21171 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21172 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21173 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21180 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21181 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21185 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21191 for(var i in group){
21192 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21193 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21198 clearInvalid : function()
21200 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21202 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21204 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21206 if (label && label.iconEl) {
21207 label.iconEl.removeClass(label.validClass);
21208 label.iconEl.removeClass(label.invalidClass);
21212 disable : function()
21214 if(this.inputType != 'radio'){
21215 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21222 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21223 _this.getActionEl().addClass(this.disabledClass);
21224 e.dom.disabled = true;
21228 this.disabled = true;
21229 this.fireEvent("disable", this);
21233 enable : function()
21235 if(this.inputType != 'radio'){
21236 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21243 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21244 _this.getActionEl().removeClass(this.disabledClass);
21245 e.dom.disabled = false;
21249 this.disabled = false;
21250 this.fireEvent("enable", this);
21254 setBoxLabel : function(v)
21259 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21265 Roo.apply(Roo.bootstrap.CheckBox, {
21270 * register a CheckBox Group
21271 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21273 register : function(checkbox)
21275 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21276 this.groups[checkbox.groupId] = {};
21279 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21283 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21287 * fetch a CheckBox Group based on the group ID
21288 * @param {string} the group ID
21289 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21291 get: function(groupId) {
21292 if (typeof(this.groups[groupId]) == 'undefined') {
21296 return this.groups[groupId] ;
21309 * @class Roo.bootstrap.Radio
21310 * @extends Roo.bootstrap.Component
21311 * Bootstrap Radio class
21312 * @cfg {String} boxLabel - the label associated
21313 * @cfg {String} value - the value of radio
21316 * Create a new Radio
21317 * @param {Object} config The config object
21319 Roo.bootstrap.Radio = function(config){
21320 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21324 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21330 getAutoCreate : function()
21334 cls : 'form-group radio',
21339 html : this.boxLabel
21347 initEvents : function()
21349 this.parent().register(this);
21351 this.el.on('click', this.onClick, this);
21355 onClick : function(e)
21357 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21358 this.setChecked(true);
21362 setChecked : function(state, suppressEvent)
21364 this.parent().setValue(this.value, suppressEvent);
21368 setBoxLabel : function(v)
21373 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21388 * @class Roo.bootstrap.SecurePass
21389 * @extends Roo.bootstrap.Input
21390 * Bootstrap SecurePass class
21394 * Create a new SecurePass
21395 * @param {Object} config The config object
21398 Roo.bootstrap.SecurePass = function (config) {
21399 // these go here, so the translation tool can replace them..
21401 PwdEmpty: "Please type a password, and then retype it to confirm.",
21402 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21403 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21404 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21405 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21406 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21407 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21408 TooWeak: "Your password is Too Weak."
21410 this.meterLabel = "Password strength:";
21411 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21412 this.meterClass = [
21413 "roo-password-meter-tooweak",
21414 "roo-password-meter-weak",
21415 "roo-password-meter-medium",
21416 "roo-password-meter-strong",
21417 "roo-password-meter-grey"
21422 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21425 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21427 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21429 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21430 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21431 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21432 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21433 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21434 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21435 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21445 * @cfg {String/Object} Label for the strength meter (defaults to
21446 * 'Password strength:')
21451 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21452 * ['Weak', 'Medium', 'Strong'])
21455 pwdStrengths: false,
21468 initEvents: function ()
21470 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21472 if (this.el.is('input[type=password]') && Roo.isSafari) {
21473 this.el.on('keydown', this.SafariOnKeyDown, this);
21476 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21479 onRender: function (ct, position)
21481 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21482 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21483 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21485 this.trigger.createChild({
21490 cls: 'roo-password-meter-grey col-xs-12',
21493 //width: this.meterWidth + 'px'
21497 cls: 'roo-password-meter-text'
21503 if (this.hideTrigger) {
21504 this.trigger.setDisplayed(false);
21506 this.setSize(this.width || '', this.height || '');
21509 onDestroy: function ()
21511 if (this.trigger) {
21512 this.trigger.removeAllListeners();
21513 this.trigger.remove();
21516 this.wrap.remove();
21518 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21521 checkStrength: function ()
21523 var pwd = this.inputEl().getValue();
21524 if (pwd == this._lastPwd) {
21529 if (this.ClientSideStrongPassword(pwd)) {
21531 } else if (this.ClientSideMediumPassword(pwd)) {
21533 } else if (this.ClientSideWeakPassword(pwd)) {
21539 Roo.log('strength1: ' + strength);
21541 //var pm = this.trigger.child('div/div/div').dom;
21542 var pm = this.trigger.child('div/div');
21543 pm.removeClass(this.meterClass);
21544 pm.addClass(this.meterClass[strength]);
21547 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21549 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21551 this._lastPwd = pwd;
21555 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21557 this._lastPwd = '';
21559 var pm = this.trigger.child('div/div');
21560 pm.removeClass(this.meterClass);
21561 pm.addClass('roo-password-meter-grey');
21564 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21567 this.inputEl().dom.type='password';
21570 validateValue: function (value)
21573 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21576 if (value.length == 0) {
21577 if (this.allowBlank) {
21578 this.clearInvalid();
21582 this.markInvalid(this.errors.PwdEmpty);
21583 this.errorMsg = this.errors.PwdEmpty;
21591 if ('[\x21-\x7e]*'.match(value)) {
21592 this.markInvalid(this.errors.PwdBadChar);
21593 this.errorMsg = this.errors.PwdBadChar;
21596 if (value.length < 6) {
21597 this.markInvalid(this.errors.PwdShort);
21598 this.errorMsg = this.errors.PwdShort;
21601 if (value.length > 16) {
21602 this.markInvalid(this.errors.PwdLong);
21603 this.errorMsg = this.errors.PwdLong;
21607 if (this.ClientSideStrongPassword(value)) {
21609 } else if (this.ClientSideMediumPassword(value)) {
21611 } else if (this.ClientSideWeakPassword(value)) {
21618 if (strength < 2) {
21619 //this.markInvalid(this.errors.TooWeak);
21620 this.errorMsg = this.errors.TooWeak;
21625 console.log('strength2: ' + strength);
21627 //var pm = this.trigger.child('div/div/div').dom;
21629 var pm = this.trigger.child('div/div');
21630 pm.removeClass(this.meterClass);
21631 pm.addClass(this.meterClass[strength]);
21633 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21635 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21637 this.errorMsg = '';
21641 CharacterSetChecks: function (type)
21644 this.fResult = false;
21647 isctype: function (character, type)
21650 case this.kCapitalLetter:
21651 if (character >= 'A' && character <= 'Z') {
21656 case this.kSmallLetter:
21657 if (character >= 'a' && character <= 'z') {
21663 if (character >= '0' && character <= '9') {
21668 case this.kPunctuation:
21669 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21680 IsLongEnough: function (pwd, size)
21682 return !(pwd == null || isNaN(size) || pwd.length < size);
21685 SpansEnoughCharacterSets: function (word, nb)
21687 if (!this.IsLongEnough(word, nb))
21692 var characterSetChecks = new Array(
21693 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21694 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21697 for (var index = 0; index < word.length; ++index) {
21698 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21699 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21700 characterSetChecks[nCharSet].fResult = true;
21707 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21708 if (characterSetChecks[nCharSet].fResult) {
21713 if (nCharSets < nb) {
21719 ClientSideStrongPassword: function (pwd)
21721 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21724 ClientSideMediumPassword: function (pwd)
21726 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21729 ClientSideWeakPassword: function (pwd)
21731 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21734 })//<script type="text/javascript">
21737 * Based Ext JS Library 1.1.1
21738 * Copyright(c) 2006-2007, Ext JS, LLC.
21744 * @class Roo.HtmlEditorCore
21745 * @extends Roo.Component
21746 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21748 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21751 Roo.HtmlEditorCore = function(config){
21754 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21759 * @event initialize
21760 * Fires when the editor is fully initialized (including the iframe)
21761 * @param {Roo.HtmlEditorCore} this
21766 * Fires when the editor is first receives the focus. Any insertion must wait
21767 * until after this event.
21768 * @param {Roo.HtmlEditorCore} this
21772 * @event beforesync
21773 * Fires before the textarea is updated with content from the editor iframe. Return false
21774 * to cancel the sync.
21775 * @param {Roo.HtmlEditorCore} this
21776 * @param {String} html
21780 * @event beforepush
21781 * Fires before the iframe editor is updated with content from the textarea. Return false
21782 * to cancel the push.
21783 * @param {Roo.HtmlEditorCore} this
21784 * @param {String} html
21789 * Fires when the textarea is updated with content from the editor iframe.
21790 * @param {Roo.HtmlEditorCore} this
21791 * @param {String} html
21796 * Fires when the iframe editor is updated with content from the textarea.
21797 * @param {Roo.HtmlEditorCore} this
21798 * @param {String} html
21803 * @event editorevent
21804 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21805 * @param {Roo.HtmlEditorCore} this
21811 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21813 // defaults : white / black...
21814 this.applyBlacklists();
21821 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21825 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21831 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21836 * @cfg {Number} height (in pixels)
21840 * @cfg {Number} width (in pixels)
21845 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21848 stylesheets: false,
21853 // private properties
21854 validationEvent : false,
21856 initialized : false,
21858 sourceEditMode : false,
21859 onFocus : Roo.emptyFn,
21861 hideMode:'offsets',
21865 // blacklist + whitelisted elements..
21872 * Protected method that will not generally be called directly. It
21873 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21874 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21876 getDocMarkup : function(){
21880 // inherit styels from page...??
21881 if (this.stylesheets === false) {
21883 Roo.get(document.head).select('style').each(function(node) {
21884 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21887 Roo.get(document.head).select('link').each(function(node) {
21888 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21891 } else if (!this.stylesheets.length) {
21893 st = '<style type="text/css">' +
21894 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21897 st = '<style type="text/css">' +
21902 st += '<style type="text/css">' +
21903 'IMG { cursor: pointer } ' +
21906 var cls = 'roo-htmleditor-body';
21908 if(this.bodyCls.length){
21909 cls += ' ' + this.bodyCls;
21912 return '<html><head>' + st +
21913 //<style type="text/css">' +
21914 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21916 ' </head><body class="' + cls + '"></body></html>';
21920 onRender : function(ct, position)
21923 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21924 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21927 this.el.dom.style.border = '0 none';
21928 this.el.dom.setAttribute('tabIndex', -1);
21929 this.el.addClass('x-hidden hide');
21933 if(Roo.isIE){ // fix IE 1px bogus margin
21934 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21938 this.frameId = Roo.id();
21942 var iframe = this.owner.wrap.createChild({
21944 cls: 'form-control', // bootstrap..
21946 name: this.frameId,
21947 frameBorder : 'no',
21948 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21953 this.iframe = iframe.dom;
21955 this.assignDocWin();
21957 this.doc.designMode = 'on';
21960 this.doc.write(this.getDocMarkup());
21964 var task = { // must defer to wait for browser to be ready
21966 //console.log("run task?" + this.doc.readyState);
21967 this.assignDocWin();
21968 if(this.doc.body || this.doc.readyState == 'complete'){
21970 this.doc.designMode="on";
21974 Roo.TaskMgr.stop(task);
21975 this.initEditor.defer(10, this);
21982 Roo.TaskMgr.start(task);
21987 onResize : function(w, h)
21989 Roo.log('resize: ' +w + ',' + h );
21990 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21994 if(typeof w == 'number'){
21996 this.iframe.style.width = w + 'px';
21998 if(typeof h == 'number'){
22000 this.iframe.style.height = h + 'px';
22002 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22009 * Toggles the editor between standard and source edit mode.
22010 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22012 toggleSourceEdit : function(sourceEditMode){
22014 this.sourceEditMode = sourceEditMode === true;
22016 if(this.sourceEditMode){
22018 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22021 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22022 //this.iframe.className = '';
22025 //this.setSize(this.owner.wrap.getSize());
22026 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22033 * Protected method that will not generally be called directly. If you need/want
22034 * custom HTML cleanup, this is the method you should override.
22035 * @param {String} html The HTML to be cleaned
22036 * return {String} The cleaned HTML
22038 cleanHtml : function(html){
22039 html = String(html);
22040 if(html.length > 5){
22041 if(Roo.isSafari){ // strip safari nonsense
22042 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22045 if(html == ' '){
22052 * HTML Editor -> Textarea
22053 * Protected method that will not generally be called directly. Syncs the contents
22054 * of the editor iframe with the textarea.
22056 syncValue : function(){
22057 if(this.initialized){
22058 var bd = (this.doc.body || this.doc.documentElement);
22059 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22060 var html = bd.innerHTML;
22062 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22063 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22065 html = '<div style="'+m[0]+'">' + html + '</div>';
22068 html = this.cleanHtml(html);
22069 // fix up the special chars.. normaly like back quotes in word...
22070 // however we do not want to do this with chinese..
22071 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22072 var cc = b.charCodeAt();
22074 (cc >= 0x4E00 && cc < 0xA000 ) ||
22075 (cc >= 0x3400 && cc < 0x4E00 ) ||
22076 (cc >= 0xf900 && cc < 0xfb00 )
22082 if(this.owner.fireEvent('beforesync', this, html) !== false){
22083 this.el.dom.value = html;
22084 this.owner.fireEvent('sync', this, html);
22090 * Protected method that will not generally be called directly. Pushes the value of the textarea
22091 * into the iframe editor.
22093 pushValue : function(){
22094 if(this.initialized){
22095 var v = this.el.dom.value.trim();
22097 // if(v.length < 1){
22101 if(this.owner.fireEvent('beforepush', this, v) !== false){
22102 var d = (this.doc.body || this.doc.documentElement);
22104 this.cleanUpPaste();
22105 this.el.dom.value = d.innerHTML;
22106 this.owner.fireEvent('push', this, v);
22112 deferFocus : function(){
22113 this.focus.defer(10, this);
22117 focus : function(){
22118 if(this.win && !this.sourceEditMode){
22125 assignDocWin: function()
22127 var iframe = this.iframe;
22130 this.doc = iframe.contentWindow.document;
22131 this.win = iframe.contentWindow;
22133 // if (!Roo.get(this.frameId)) {
22136 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22137 // this.win = Roo.get(this.frameId).dom.contentWindow;
22139 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22143 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22144 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22149 initEditor : function(){
22150 //console.log("INIT EDITOR");
22151 this.assignDocWin();
22155 this.doc.designMode="on";
22157 this.doc.write(this.getDocMarkup());
22160 var dbody = (this.doc.body || this.doc.documentElement);
22161 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22162 // this copies styles from the containing element into thsi one..
22163 // not sure why we need all of this..
22164 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22166 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22167 //ss['background-attachment'] = 'fixed'; // w3c
22168 dbody.bgProperties = 'fixed'; // ie
22169 //Roo.DomHelper.applyStyles(dbody, ss);
22170 Roo.EventManager.on(this.doc, {
22171 //'mousedown': this.onEditorEvent,
22172 'mouseup': this.onEditorEvent,
22173 'dblclick': this.onEditorEvent,
22174 'click': this.onEditorEvent,
22175 'keyup': this.onEditorEvent,
22180 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22182 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22183 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22185 this.initialized = true;
22187 this.owner.fireEvent('initialize', this);
22192 onDestroy : function(){
22198 //for (var i =0; i < this.toolbars.length;i++) {
22199 // // fixme - ask toolbars for heights?
22200 // this.toolbars[i].onDestroy();
22203 //this.wrap.dom.innerHTML = '';
22204 //this.wrap.remove();
22209 onFirstFocus : function(){
22211 this.assignDocWin();
22214 this.activated = true;
22217 if(Roo.isGecko){ // prevent silly gecko errors
22219 var s = this.win.getSelection();
22220 if(!s.focusNode || s.focusNode.nodeType != 3){
22221 var r = s.getRangeAt(0);
22222 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22227 this.execCmd('useCSS', true);
22228 this.execCmd('styleWithCSS', false);
22231 this.owner.fireEvent('activate', this);
22235 adjustFont: function(btn){
22236 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22237 //if(Roo.isSafari){ // safari
22240 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22241 if(Roo.isSafari){ // safari
22242 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22243 v = (v < 10) ? 10 : v;
22244 v = (v > 48) ? 48 : v;
22245 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22250 v = Math.max(1, v+adjust);
22252 this.execCmd('FontSize', v );
22255 onEditorEvent : function(e)
22257 this.owner.fireEvent('editorevent', this, e);
22258 // this.updateToolbar();
22259 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22262 insertTag : function(tg)
22264 // could be a bit smarter... -> wrap the current selected tRoo..
22265 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22267 range = this.createRange(this.getSelection());
22268 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22269 wrappingNode.appendChild(range.extractContents());
22270 range.insertNode(wrappingNode);
22277 this.execCmd("formatblock", tg);
22281 insertText : function(txt)
22285 var range = this.createRange();
22286 range.deleteContents();
22287 //alert(Sender.getAttribute('label'));
22289 range.insertNode(this.doc.createTextNode(txt));
22295 * Executes a Midas editor command on the editor document and performs necessary focus and
22296 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22297 * @param {String} cmd The Midas command
22298 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22300 relayCmd : function(cmd, value){
22302 this.execCmd(cmd, value);
22303 this.owner.fireEvent('editorevent', this);
22304 //this.updateToolbar();
22305 this.owner.deferFocus();
22309 * Executes a Midas editor command directly on the editor document.
22310 * For visual commands, you should use {@link #relayCmd} instead.
22311 * <b>This should only be called after the editor is initialized.</b>
22312 * @param {String} cmd The Midas command
22313 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22315 execCmd : function(cmd, value){
22316 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22323 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22325 * @param {String} text | dom node..
22327 insertAtCursor : function(text)
22330 if(!this.activated){
22336 var r = this.doc.selection.createRange();
22347 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22351 // from jquery ui (MIT licenced)
22353 var win = this.win;
22355 if (win.getSelection && win.getSelection().getRangeAt) {
22356 range = win.getSelection().getRangeAt(0);
22357 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22358 range.insertNode(node);
22359 } else if (win.document.selection && win.document.selection.createRange) {
22360 // no firefox support
22361 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22362 win.document.selection.createRange().pasteHTML(txt);
22364 // no firefox support
22365 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22366 this.execCmd('InsertHTML', txt);
22375 mozKeyPress : function(e){
22377 var c = e.getCharCode(), cmd;
22380 c = String.fromCharCode(c).toLowerCase();
22394 this.cleanUpPaste.defer(100, this);
22402 e.preventDefault();
22410 fixKeys : function(){ // load time branching for fastest keydown performance
22412 return function(e){
22413 var k = e.getKey(), r;
22416 r = this.doc.selection.createRange();
22419 r.pasteHTML('    ');
22426 r = this.doc.selection.createRange();
22428 var target = r.parentElement();
22429 if(!target || target.tagName.toLowerCase() != 'li'){
22431 r.pasteHTML('<br />');
22437 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22438 this.cleanUpPaste.defer(100, this);
22444 }else if(Roo.isOpera){
22445 return function(e){
22446 var k = e.getKey();
22450 this.execCmd('InsertHTML','    ');
22453 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22454 this.cleanUpPaste.defer(100, this);
22459 }else if(Roo.isSafari){
22460 return function(e){
22461 var k = e.getKey();
22465 this.execCmd('InsertText','\t');
22469 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22470 this.cleanUpPaste.defer(100, this);
22478 getAllAncestors: function()
22480 var p = this.getSelectedNode();
22483 a.push(p); // push blank onto stack..
22484 p = this.getParentElement();
22488 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22492 a.push(this.doc.body);
22496 lastSelNode : false,
22499 getSelection : function()
22501 this.assignDocWin();
22502 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22505 getSelectedNode: function()
22507 // this may only work on Gecko!!!
22509 // should we cache this!!!!
22514 var range = this.createRange(this.getSelection()).cloneRange();
22517 var parent = range.parentElement();
22519 var testRange = range.duplicate();
22520 testRange.moveToElementText(parent);
22521 if (testRange.inRange(range)) {
22524 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22527 parent = parent.parentElement;
22532 // is ancestor a text element.
22533 var ac = range.commonAncestorContainer;
22534 if (ac.nodeType == 3) {
22535 ac = ac.parentNode;
22538 var ar = ac.childNodes;
22541 var other_nodes = [];
22542 var has_other_nodes = false;
22543 for (var i=0;i<ar.length;i++) {
22544 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22547 // fullly contained node.
22549 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22554 // probably selected..
22555 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22556 other_nodes.push(ar[i]);
22560 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22565 has_other_nodes = true;
22567 if (!nodes.length && other_nodes.length) {
22568 nodes= other_nodes;
22570 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22576 createRange: function(sel)
22578 // this has strange effects when using with
22579 // top toolbar - not sure if it's a great idea.
22580 //this.editor.contentWindow.focus();
22581 if (typeof sel != "undefined") {
22583 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22585 return this.doc.createRange();
22588 return this.doc.createRange();
22591 getParentElement: function()
22594 this.assignDocWin();
22595 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22597 var range = this.createRange(sel);
22600 var p = range.commonAncestorContainer;
22601 while (p.nodeType == 3) { // text node
22612 * Range intersection.. the hard stuff...
22616 * [ -- selected range --- ]
22620 * if end is before start or hits it. fail.
22621 * if start is after end or hits it fail.
22623 * if either hits (but other is outside. - then it's not
22629 // @see http://www.thismuchiknow.co.uk/?p=64.
22630 rangeIntersectsNode : function(range, node)
22632 var nodeRange = node.ownerDocument.createRange();
22634 nodeRange.selectNode(node);
22636 nodeRange.selectNodeContents(node);
22639 var rangeStartRange = range.cloneRange();
22640 rangeStartRange.collapse(true);
22642 var rangeEndRange = range.cloneRange();
22643 rangeEndRange.collapse(false);
22645 var nodeStartRange = nodeRange.cloneRange();
22646 nodeStartRange.collapse(true);
22648 var nodeEndRange = nodeRange.cloneRange();
22649 nodeEndRange.collapse(false);
22651 return rangeStartRange.compareBoundaryPoints(
22652 Range.START_TO_START, nodeEndRange) == -1 &&
22653 rangeEndRange.compareBoundaryPoints(
22654 Range.START_TO_START, nodeStartRange) == 1;
22658 rangeCompareNode : function(range, node)
22660 var nodeRange = node.ownerDocument.createRange();
22662 nodeRange.selectNode(node);
22664 nodeRange.selectNodeContents(node);
22668 range.collapse(true);
22670 nodeRange.collapse(true);
22672 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22673 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22675 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22677 var nodeIsBefore = ss == 1;
22678 var nodeIsAfter = ee == -1;
22680 if (nodeIsBefore && nodeIsAfter) {
22683 if (!nodeIsBefore && nodeIsAfter) {
22684 return 1; //right trailed.
22687 if (nodeIsBefore && !nodeIsAfter) {
22688 return 2; // left trailed.
22694 // private? - in a new class?
22695 cleanUpPaste : function()
22697 // cleans up the whole document..
22698 Roo.log('cleanuppaste');
22700 this.cleanUpChildren(this.doc.body);
22701 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22702 if (clean != this.doc.body.innerHTML) {
22703 this.doc.body.innerHTML = clean;
22708 cleanWordChars : function(input) {// change the chars to hex code
22709 var he = Roo.HtmlEditorCore;
22711 var output = input;
22712 Roo.each(he.swapCodes, function(sw) {
22713 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22715 output = output.replace(swapper, sw[1]);
22722 cleanUpChildren : function (n)
22724 if (!n.childNodes.length) {
22727 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22728 this.cleanUpChild(n.childNodes[i]);
22735 cleanUpChild : function (node)
22738 //console.log(node);
22739 if (node.nodeName == "#text") {
22740 // clean up silly Windows -- stuff?
22743 if (node.nodeName == "#comment") {
22744 node.parentNode.removeChild(node);
22745 // clean up silly Windows -- stuff?
22748 var lcname = node.tagName.toLowerCase();
22749 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22750 // whitelist of tags..
22752 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22754 node.parentNode.removeChild(node);
22759 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22761 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22762 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22764 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22765 // remove_keep_children = true;
22768 if (remove_keep_children) {
22769 this.cleanUpChildren(node);
22770 // inserts everything just before this node...
22771 while (node.childNodes.length) {
22772 var cn = node.childNodes[0];
22773 node.removeChild(cn);
22774 node.parentNode.insertBefore(cn, node);
22776 node.parentNode.removeChild(node);
22780 if (!node.attributes || !node.attributes.length) {
22781 this.cleanUpChildren(node);
22785 function cleanAttr(n,v)
22788 if (v.match(/^\./) || v.match(/^\//)) {
22791 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22794 if (v.match(/^#/)) {
22797 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22798 node.removeAttribute(n);
22802 var cwhite = this.cwhite;
22803 var cblack = this.cblack;
22805 function cleanStyle(n,v)
22807 if (v.match(/expression/)) { //XSS?? should we even bother..
22808 node.removeAttribute(n);
22812 var parts = v.split(/;/);
22815 Roo.each(parts, function(p) {
22816 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22820 var l = p.split(':').shift().replace(/\s+/g,'');
22821 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22823 if ( cwhite.length && cblack.indexOf(l) > -1) {
22824 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22825 //node.removeAttribute(n);
22829 // only allow 'c whitelisted system attributes'
22830 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22831 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22832 //node.removeAttribute(n);
22842 if (clean.length) {
22843 node.setAttribute(n, clean.join(';'));
22845 node.removeAttribute(n);
22851 for (var i = node.attributes.length-1; i > -1 ; i--) {
22852 var a = node.attributes[i];
22855 if (a.name.toLowerCase().substr(0,2)=='on') {
22856 node.removeAttribute(a.name);
22859 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22860 node.removeAttribute(a.name);
22863 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22864 cleanAttr(a.name,a.value); // fixme..
22867 if (a.name == 'style') {
22868 cleanStyle(a.name,a.value);
22871 /// clean up MS crap..
22872 // tecnically this should be a list of valid class'es..
22875 if (a.name == 'class') {
22876 if (a.value.match(/^Mso/)) {
22877 node.className = '';
22880 if (a.value.match(/^body$/)) {
22881 node.className = '';
22892 this.cleanUpChildren(node);
22898 * Clean up MS wordisms...
22900 cleanWord : function(node)
22905 this.cleanWord(this.doc.body);
22908 if (node.nodeName == "#text") {
22909 // clean up silly Windows -- stuff?
22912 if (node.nodeName == "#comment") {
22913 node.parentNode.removeChild(node);
22914 // clean up silly Windows -- stuff?
22918 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22919 node.parentNode.removeChild(node);
22923 // remove - but keep children..
22924 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22925 while (node.childNodes.length) {
22926 var cn = node.childNodes[0];
22927 node.removeChild(cn);
22928 node.parentNode.insertBefore(cn, node);
22930 node.parentNode.removeChild(node);
22931 this.iterateChildren(node, this.cleanWord);
22935 if (node.className.length) {
22937 var cn = node.className.split(/\W+/);
22939 Roo.each(cn, function(cls) {
22940 if (cls.match(/Mso[a-zA-Z]+/)) {
22945 node.className = cna.length ? cna.join(' ') : '';
22947 node.removeAttribute("class");
22951 if (node.hasAttribute("lang")) {
22952 node.removeAttribute("lang");
22955 if (node.hasAttribute("style")) {
22957 var styles = node.getAttribute("style").split(";");
22959 Roo.each(styles, function(s) {
22960 if (!s.match(/:/)) {
22963 var kv = s.split(":");
22964 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22967 // what ever is left... we allow.
22970 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22971 if (!nstyle.length) {
22972 node.removeAttribute('style');
22975 this.iterateChildren(node, this.cleanWord);
22981 * iterateChildren of a Node, calling fn each time, using this as the scole..
22982 * @param {DomNode} node node to iterate children of.
22983 * @param {Function} fn method of this class to call on each item.
22985 iterateChildren : function(node, fn)
22987 if (!node.childNodes.length) {
22990 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22991 fn.call(this, node.childNodes[i])
22997 * cleanTableWidths.
22999 * Quite often pasting from word etc.. results in tables with column and widths.
23000 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23003 cleanTableWidths : function(node)
23008 this.cleanTableWidths(this.doc.body);
23013 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23016 Roo.log(node.tagName);
23017 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23018 this.iterateChildren(node, this.cleanTableWidths);
23021 if (node.hasAttribute('width')) {
23022 node.removeAttribute('width');
23026 if (node.hasAttribute("style")) {
23029 var styles = node.getAttribute("style").split(";");
23031 Roo.each(styles, function(s) {
23032 if (!s.match(/:/)) {
23035 var kv = s.split(":");
23036 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23039 // what ever is left... we allow.
23042 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23043 if (!nstyle.length) {
23044 node.removeAttribute('style');
23048 this.iterateChildren(node, this.cleanTableWidths);
23056 domToHTML : function(currentElement, depth, nopadtext) {
23058 depth = depth || 0;
23059 nopadtext = nopadtext || false;
23061 if (!currentElement) {
23062 return this.domToHTML(this.doc.body);
23065 //Roo.log(currentElement);
23067 var allText = false;
23068 var nodeName = currentElement.nodeName;
23069 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23071 if (nodeName == '#text') {
23073 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23078 if (nodeName != 'BODY') {
23081 // Prints the node tagName, such as <A>, <IMG>, etc
23084 for(i = 0; i < currentElement.attributes.length;i++) {
23086 var aname = currentElement.attributes.item(i).name;
23087 if (!currentElement.attributes.item(i).value.length) {
23090 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23093 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23102 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23105 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23110 // Traverse the tree
23112 var currentElementChild = currentElement.childNodes.item(i);
23113 var allText = true;
23114 var innerHTML = '';
23116 while (currentElementChild) {
23117 // Formatting code (indent the tree so it looks nice on the screen)
23118 var nopad = nopadtext;
23119 if (lastnode == 'SPAN') {
23123 if (currentElementChild.nodeName == '#text') {
23124 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23125 toadd = nopadtext ? toadd : toadd.trim();
23126 if (!nopad && toadd.length > 80) {
23127 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23129 innerHTML += toadd;
23132 currentElementChild = currentElement.childNodes.item(i);
23138 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23140 // Recursively traverse the tree structure of the child node
23141 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23142 lastnode = currentElementChild.nodeName;
23144 currentElementChild=currentElement.childNodes.item(i);
23150 // The remaining code is mostly for formatting the tree
23151 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23156 ret+= "</"+tagName+">";
23162 applyBlacklists : function()
23164 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23165 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23169 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23170 if (b.indexOf(tag) > -1) {
23173 this.white.push(tag);
23177 Roo.each(w, function(tag) {
23178 if (b.indexOf(tag) > -1) {
23181 if (this.white.indexOf(tag) > -1) {
23184 this.white.push(tag);
23189 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23190 if (w.indexOf(tag) > -1) {
23193 this.black.push(tag);
23197 Roo.each(b, function(tag) {
23198 if (w.indexOf(tag) > -1) {
23201 if (this.black.indexOf(tag) > -1) {
23204 this.black.push(tag);
23209 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23210 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23214 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23215 if (b.indexOf(tag) > -1) {
23218 this.cwhite.push(tag);
23222 Roo.each(w, function(tag) {
23223 if (b.indexOf(tag) > -1) {
23226 if (this.cwhite.indexOf(tag) > -1) {
23229 this.cwhite.push(tag);
23234 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23235 if (w.indexOf(tag) > -1) {
23238 this.cblack.push(tag);
23242 Roo.each(b, function(tag) {
23243 if (w.indexOf(tag) > -1) {
23246 if (this.cblack.indexOf(tag) > -1) {
23249 this.cblack.push(tag);
23254 setStylesheets : function(stylesheets)
23256 if(typeof(stylesheets) == 'string'){
23257 Roo.get(this.iframe.contentDocument.head).createChild({
23259 rel : 'stylesheet',
23268 Roo.each(stylesheets, function(s) {
23273 Roo.get(_this.iframe.contentDocument.head).createChild({
23275 rel : 'stylesheet',
23284 removeStylesheets : function()
23288 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23293 setStyle : function(style)
23295 Roo.get(this.iframe.contentDocument.head).createChild({
23304 // hide stuff that is not compatible
23318 * @event specialkey
23322 * @cfg {String} fieldClass @hide
23325 * @cfg {String} focusClass @hide
23328 * @cfg {String} autoCreate @hide
23331 * @cfg {String} inputType @hide
23334 * @cfg {String} invalidClass @hide
23337 * @cfg {String} invalidText @hide
23340 * @cfg {String} msgFx @hide
23343 * @cfg {String} validateOnBlur @hide
23347 Roo.HtmlEditorCore.white = [
23348 'area', 'br', 'img', 'input', 'hr', 'wbr',
23350 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23351 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23352 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23353 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23354 'table', 'ul', 'xmp',
23356 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23359 'dir', 'menu', 'ol', 'ul', 'dl',
23365 Roo.HtmlEditorCore.black = [
23366 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23368 'base', 'basefont', 'bgsound', 'blink', 'body',
23369 'frame', 'frameset', 'head', 'html', 'ilayer',
23370 'iframe', 'layer', 'link', 'meta', 'object',
23371 'script', 'style' ,'title', 'xml' // clean later..
23373 Roo.HtmlEditorCore.clean = [
23374 'script', 'style', 'title', 'xml'
23376 Roo.HtmlEditorCore.remove = [
23381 Roo.HtmlEditorCore.ablack = [
23385 Roo.HtmlEditorCore.aclean = [
23386 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23390 Roo.HtmlEditorCore.pwhite= [
23391 'http', 'https', 'mailto'
23394 // white listed style attributes.
23395 Roo.HtmlEditorCore.cwhite= [
23396 // 'text-align', /// default is to allow most things..
23402 // black listed style attributes.
23403 Roo.HtmlEditorCore.cblack= [
23404 // 'font-size' -- this can be set by the project
23408 Roo.HtmlEditorCore.swapCodes =[
23427 * @class Roo.bootstrap.HtmlEditor
23428 * @extends Roo.bootstrap.TextArea
23429 * Bootstrap HtmlEditor class
23432 * Create a new HtmlEditor
23433 * @param {Object} config The config object
23436 Roo.bootstrap.HtmlEditor = function(config){
23437 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23438 if (!this.toolbars) {
23439 this.toolbars = [];
23442 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23445 * @event initialize
23446 * Fires when the editor is fully initialized (including the iframe)
23447 * @param {HtmlEditor} this
23452 * Fires when the editor is first receives the focus. Any insertion must wait
23453 * until after this event.
23454 * @param {HtmlEditor} this
23458 * @event beforesync
23459 * Fires before the textarea is updated with content from the editor iframe. Return false
23460 * to cancel the sync.
23461 * @param {HtmlEditor} this
23462 * @param {String} html
23466 * @event beforepush
23467 * Fires before the iframe editor is updated with content from the textarea. Return false
23468 * to cancel the push.
23469 * @param {HtmlEditor} this
23470 * @param {String} html
23475 * Fires when the textarea is updated with content from the editor iframe.
23476 * @param {HtmlEditor} this
23477 * @param {String} html
23482 * Fires when the iframe editor is updated with content from the textarea.
23483 * @param {HtmlEditor} this
23484 * @param {String} html
23488 * @event editmodechange
23489 * Fires when the editor switches edit modes
23490 * @param {HtmlEditor} this
23491 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23493 editmodechange: true,
23495 * @event editorevent
23496 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23497 * @param {HtmlEditor} this
23501 * @event firstfocus
23502 * Fires when on first focus - needed by toolbars..
23503 * @param {HtmlEditor} this
23508 * Auto save the htmlEditor value as a file into Events
23509 * @param {HtmlEditor} this
23513 * @event savedpreview
23514 * preview the saved version of htmlEditor
23515 * @param {HtmlEditor} this
23522 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23526 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23531 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23536 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23541 * @cfg {Number} height (in pixels)
23545 * @cfg {Number} width (in pixels)
23550 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23553 stylesheets: false,
23558 // private properties
23559 validationEvent : false,
23561 initialized : false,
23564 onFocus : Roo.emptyFn,
23566 hideMode:'offsets',
23568 tbContainer : false,
23572 toolbarContainer :function() {
23573 return this.wrap.select('.x-html-editor-tb',true).first();
23577 * Protected method that will not generally be called directly. It
23578 * is called when the editor creates its toolbar. Override this method if you need to
23579 * add custom toolbar buttons.
23580 * @param {HtmlEditor} editor
23582 createToolbar : function(){
23583 Roo.log('renewing');
23584 Roo.log("create toolbars");
23586 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23587 this.toolbars[0].render(this.toolbarContainer());
23591 // if (!editor.toolbars || !editor.toolbars.length) {
23592 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23595 // for (var i =0 ; i < editor.toolbars.length;i++) {
23596 // editor.toolbars[i] = Roo.factory(
23597 // typeof(editor.toolbars[i]) == 'string' ?
23598 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23599 // Roo.bootstrap.HtmlEditor);
23600 // editor.toolbars[i].init(editor);
23606 onRender : function(ct, position)
23608 // Roo.log("Call onRender: " + this.xtype);
23610 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23612 this.wrap = this.inputEl().wrap({
23613 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23616 this.editorcore.onRender(ct, position);
23618 if (this.resizable) {
23619 this.resizeEl = new Roo.Resizable(this.wrap, {
23623 minHeight : this.height,
23624 height: this.height,
23625 handles : this.resizable,
23628 resize : function(r, w, h) {
23629 _t.onResize(w,h); // -something
23635 this.createToolbar(this);
23638 if(!this.width && this.resizable){
23639 this.setSize(this.wrap.getSize());
23641 if (this.resizeEl) {
23642 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23643 // should trigger onReize..
23649 onResize : function(w, h)
23651 Roo.log('resize: ' +w + ',' + h );
23652 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23656 if(this.inputEl() ){
23657 if(typeof w == 'number'){
23658 var aw = w - this.wrap.getFrameWidth('lr');
23659 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23662 if(typeof h == 'number'){
23663 var tbh = -11; // fixme it needs to tool bar size!
23664 for (var i =0; i < this.toolbars.length;i++) {
23665 // fixme - ask toolbars for heights?
23666 tbh += this.toolbars[i].el.getHeight();
23667 //if (this.toolbars[i].footer) {
23668 // tbh += this.toolbars[i].footer.el.getHeight();
23676 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23677 ah -= 5; // knock a few pixes off for look..
23678 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23682 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23683 this.editorcore.onResize(ew,eh);
23688 * Toggles the editor between standard and source edit mode.
23689 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23691 toggleSourceEdit : function(sourceEditMode)
23693 this.editorcore.toggleSourceEdit(sourceEditMode);
23695 if(this.editorcore.sourceEditMode){
23696 Roo.log('editor - showing textarea');
23699 // Roo.log(this.syncValue());
23701 this.inputEl().removeClass(['hide', 'x-hidden']);
23702 this.inputEl().dom.removeAttribute('tabIndex');
23703 this.inputEl().focus();
23705 Roo.log('editor - hiding textarea');
23707 // Roo.log(this.pushValue());
23710 this.inputEl().addClass(['hide', 'x-hidden']);
23711 this.inputEl().dom.setAttribute('tabIndex', -1);
23712 //this.deferFocus();
23715 if(this.resizable){
23716 this.setSize(this.wrap.getSize());
23719 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23722 // private (for BoxComponent)
23723 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23725 // private (for BoxComponent)
23726 getResizeEl : function(){
23730 // private (for BoxComponent)
23731 getPositionEl : function(){
23736 initEvents : function(){
23737 this.originalValue = this.getValue();
23741 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23744 // markInvalid : Roo.emptyFn,
23746 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23749 // clearInvalid : Roo.emptyFn,
23751 setValue : function(v){
23752 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23753 this.editorcore.pushValue();
23758 deferFocus : function(){
23759 this.focus.defer(10, this);
23763 focus : function(){
23764 this.editorcore.focus();
23770 onDestroy : function(){
23776 for (var i =0; i < this.toolbars.length;i++) {
23777 // fixme - ask toolbars for heights?
23778 this.toolbars[i].onDestroy();
23781 this.wrap.dom.innerHTML = '';
23782 this.wrap.remove();
23787 onFirstFocus : function(){
23788 //Roo.log("onFirstFocus");
23789 this.editorcore.onFirstFocus();
23790 for (var i =0; i < this.toolbars.length;i++) {
23791 this.toolbars[i].onFirstFocus();
23797 syncValue : function()
23799 this.editorcore.syncValue();
23802 pushValue : function()
23804 this.editorcore.pushValue();
23808 // hide stuff that is not compatible
23822 * @event specialkey
23826 * @cfg {String} fieldClass @hide
23829 * @cfg {String} focusClass @hide
23832 * @cfg {String} autoCreate @hide
23835 * @cfg {String} inputType @hide
23838 * @cfg {String} invalidClass @hide
23841 * @cfg {String} invalidText @hide
23844 * @cfg {String} msgFx @hide
23847 * @cfg {String} validateOnBlur @hide
23856 Roo.namespace('Roo.bootstrap.htmleditor');
23858 * @class Roo.bootstrap.HtmlEditorToolbar1
23863 new Roo.bootstrap.HtmlEditor({
23866 new Roo.bootstrap.HtmlEditorToolbar1({
23867 disable : { fonts: 1 , format: 1, ..., ... , ...],
23873 * @cfg {Object} disable List of elements to disable..
23874 * @cfg {Array} btns List of additional buttons.
23878 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23881 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23884 Roo.apply(this, config);
23886 // default disabled, based on 'good practice'..
23887 this.disable = this.disable || {};
23888 Roo.applyIf(this.disable, {
23891 specialElements : true
23893 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23895 this.editor = config.editor;
23896 this.editorcore = config.editor.editorcore;
23898 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23900 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23901 // dont call parent... till later.
23903 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23908 editorcore : false,
23913 "h1","h2","h3","h4","h5","h6",
23915 "abbr", "acronym", "address", "cite", "samp", "var",
23919 onRender : function(ct, position)
23921 // Roo.log("Call onRender: " + this.xtype);
23923 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23925 this.el.dom.style.marginBottom = '0';
23927 var editorcore = this.editorcore;
23928 var editor= this.editor;
23931 var btn = function(id,cmd , toggle, handler, html){
23933 var event = toggle ? 'toggle' : 'click';
23938 xns: Roo.bootstrap,
23941 enableToggle:toggle !== false,
23943 pressed : toggle ? false : null,
23946 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23947 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23953 // var cb_box = function...
23958 xns: Roo.bootstrap,
23959 glyphicon : 'font',
23963 xns: Roo.bootstrap,
23967 Roo.each(this.formats, function(f) {
23968 style.menu.items.push({
23970 xns: Roo.bootstrap,
23971 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23976 editorcore.insertTag(this.tagname);
23983 children.push(style);
23985 btn('bold',false,true);
23986 btn('italic',false,true);
23987 btn('align-left', 'justifyleft',true);
23988 btn('align-center', 'justifycenter',true);
23989 btn('align-right' , 'justifyright',true);
23990 btn('link', false, false, function(btn) {
23991 //Roo.log("create link?");
23992 var url = prompt(this.createLinkText, this.defaultLinkValue);
23993 if(url && url != 'http:/'+'/'){
23994 this.editorcore.relayCmd('createlink', url);
23997 btn('list','insertunorderedlist',true);
23998 btn('pencil', false,true, function(btn){
24000 this.toggleSourceEdit(btn.pressed);
24003 if (this.editor.btns.length > 0) {
24004 for (var i = 0; i<this.editor.btns.length; i++) {
24005 children.push(this.editor.btns[i]);
24013 xns: Roo.bootstrap,
24018 xns: Roo.bootstrap,
24023 cog.menu.items.push({
24025 xns: Roo.bootstrap,
24026 html : Clean styles,
24031 editorcore.insertTag(this.tagname);
24040 this.xtype = 'NavSimplebar';
24042 for(var i=0;i< children.length;i++) {
24044 this.buttons.add(this.addxtypeChild(children[i]));
24048 editor.on('editorevent', this.updateToolbar, this);
24050 onBtnClick : function(id)
24052 this.editorcore.relayCmd(id);
24053 this.editorcore.focus();
24057 * Protected method that will not generally be called directly. It triggers
24058 * a toolbar update by reading the markup state of the current selection in the editor.
24060 updateToolbar: function(){
24062 if(!this.editorcore.activated){
24063 this.editor.onFirstFocus(); // is this neeed?
24067 var btns = this.buttons;
24068 var doc = this.editorcore.doc;
24069 btns.get('bold').setActive(doc.queryCommandState('bold'));
24070 btns.get('italic').setActive(doc.queryCommandState('italic'));
24071 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24073 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24074 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24075 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24077 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24078 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24081 var ans = this.editorcore.getAllAncestors();
24082 if (this.formatCombo) {
24085 var store = this.formatCombo.store;
24086 this.formatCombo.setValue("");
24087 for (var i =0; i < ans.length;i++) {
24088 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24090 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24098 // hides menus... - so this cant be on a menu...
24099 Roo.bootstrap.MenuMgr.hideAll();
24101 Roo.bootstrap.MenuMgr.hideAll();
24102 //this.editorsyncValue();
24104 onFirstFocus: function() {
24105 this.buttons.each(function(item){
24109 toggleSourceEdit : function(sourceEditMode){
24112 if(sourceEditMode){
24113 Roo.log("disabling buttons");
24114 this.buttons.each( function(item){
24115 if(item.cmd != 'pencil'){
24121 Roo.log("enabling buttons");
24122 if(this.editorcore.initialized){
24123 this.buttons.each( function(item){
24129 Roo.log("calling toggole on editor");
24130 // tell the editor that it's been pressed..
24131 this.editor.toggleSourceEdit(sourceEditMode);
24141 * @class Roo.bootstrap.Table.AbstractSelectionModel
24142 * @extends Roo.util.Observable
24143 * Abstract base class for grid SelectionModels. It provides the interface that should be
24144 * implemented by descendant classes. This class should not be directly instantiated.
24147 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24148 this.locked = false;
24149 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24153 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24154 /** @ignore Called by the grid automatically. Do not call directly. */
24155 init : function(grid){
24161 * Locks the selections.
24164 this.locked = true;
24168 * Unlocks the selections.
24170 unlock : function(){
24171 this.locked = false;
24175 * Returns true if the selections are locked.
24176 * @return {Boolean}
24178 isLocked : function(){
24179 return this.locked;
24183 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24184 * @class Roo.bootstrap.Table.RowSelectionModel
24185 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24186 * It supports multiple selections and keyboard selection/navigation.
24188 * @param {Object} config
24191 Roo.bootstrap.Table.RowSelectionModel = function(config){
24192 Roo.apply(this, config);
24193 this.selections = new Roo.util.MixedCollection(false, function(o){
24198 this.lastActive = false;
24202 * @event selectionchange
24203 * Fires when the selection changes
24204 * @param {SelectionModel} this
24206 "selectionchange" : true,
24208 * @event afterselectionchange
24209 * Fires after the selection changes (eg. by key press or clicking)
24210 * @param {SelectionModel} this
24212 "afterselectionchange" : true,
24214 * @event beforerowselect
24215 * Fires when a row is selected being selected, return false to cancel.
24216 * @param {SelectionModel} this
24217 * @param {Number} rowIndex The selected index
24218 * @param {Boolean} keepExisting False if other selections will be cleared
24220 "beforerowselect" : true,
24223 * Fires when a row is selected.
24224 * @param {SelectionModel} this
24225 * @param {Number} rowIndex The selected index
24226 * @param {Roo.data.Record} r The record
24228 "rowselect" : true,
24230 * @event rowdeselect
24231 * Fires when a row is deselected.
24232 * @param {SelectionModel} this
24233 * @param {Number} rowIndex The selected index
24235 "rowdeselect" : true
24237 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24238 this.locked = false;
24241 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24243 * @cfg {Boolean} singleSelect
24244 * True to allow selection of only one row at a time (defaults to false)
24246 singleSelect : false,
24249 initEvents : function()
24252 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24253 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24254 //}else{ // allow click to work like normal
24255 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24257 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24258 this.grid.on("rowclick", this.handleMouseDown, this);
24260 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24261 "up" : function(e){
24263 this.selectPrevious(e.shiftKey);
24264 }else if(this.last !== false && this.lastActive !== false){
24265 var last = this.last;
24266 this.selectRange(this.last, this.lastActive-1);
24267 this.grid.getView().focusRow(this.lastActive);
24268 if(last !== false){
24272 this.selectFirstRow();
24274 this.fireEvent("afterselectionchange", this);
24276 "down" : function(e){
24278 this.selectNext(e.shiftKey);
24279 }else if(this.last !== false && this.lastActive !== false){
24280 var last = this.last;
24281 this.selectRange(this.last, this.lastActive+1);
24282 this.grid.getView().focusRow(this.lastActive);
24283 if(last !== false){
24287 this.selectFirstRow();
24289 this.fireEvent("afterselectionchange", this);
24293 this.grid.store.on('load', function(){
24294 this.selections.clear();
24297 var view = this.grid.view;
24298 view.on("refresh", this.onRefresh, this);
24299 view.on("rowupdated", this.onRowUpdated, this);
24300 view.on("rowremoved", this.onRemove, this);
24305 onRefresh : function()
24307 var ds = this.grid.store, i, v = this.grid.view;
24308 var s = this.selections;
24309 s.each(function(r){
24310 if((i = ds.indexOfId(r.id)) != -1){
24319 onRemove : function(v, index, r){
24320 this.selections.remove(r);
24324 onRowUpdated : function(v, index, r){
24325 if(this.isSelected(r)){
24326 v.onRowSelect(index);
24332 * @param {Array} records The records to select
24333 * @param {Boolean} keepExisting (optional) True to keep existing selections
24335 selectRecords : function(records, keepExisting)
24338 this.clearSelections();
24340 var ds = this.grid.store;
24341 for(var i = 0, len = records.length; i < len; i++){
24342 this.selectRow(ds.indexOf(records[i]), true);
24347 * Gets the number of selected rows.
24350 getCount : function(){
24351 return this.selections.length;
24355 * Selects the first row in the grid.
24357 selectFirstRow : function(){
24362 * Select the last row.
24363 * @param {Boolean} keepExisting (optional) True to keep existing selections
24365 selectLastRow : function(keepExisting){
24366 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24367 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24371 * Selects the row immediately following the last selected row.
24372 * @param {Boolean} keepExisting (optional) True to keep existing selections
24374 selectNext : function(keepExisting)
24376 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24377 this.selectRow(this.last+1, keepExisting);
24378 this.grid.getView().focusRow(this.last);
24383 * Selects the row that precedes the last selected row.
24384 * @param {Boolean} keepExisting (optional) True to keep existing selections
24386 selectPrevious : function(keepExisting){
24388 this.selectRow(this.last-1, keepExisting);
24389 this.grid.getView().focusRow(this.last);
24394 * Returns the selected records
24395 * @return {Array} Array of selected records
24397 getSelections : function(){
24398 return [].concat(this.selections.items);
24402 * Returns the first selected record.
24405 getSelected : function(){
24406 return this.selections.itemAt(0);
24411 * Clears all selections.
24413 clearSelections : function(fast)
24419 var ds = this.grid.store;
24420 var s = this.selections;
24421 s.each(function(r){
24422 this.deselectRow(ds.indexOfId(r.id));
24426 this.selections.clear();
24433 * Selects all rows.
24435 selectAll : function(){
24439 this.selections.clear();
24440 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24441 this.selectRow(i, true);
24446 * Returns True if there is a selection.
24447 * @return {Boolean}
24449 hasSelection : function(){
24450 return this.selections.length > 0;
24454 * Returns True if the specified row is selected.
24455 * @param {Number/Record} record The record or index of the record to check
24456 * @return {Boolean}
24458 isSelected : function(index){
24459 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24460 return (r && this.selections.key(r.id) ? true : false);
24464 * Returns True if the specified record id is selected.
24465 * @param {String} id The id of record to check
24466 * @return {Boolean}
24468 isIdSelected : function(id){
24469 return (this.selections.key(id) ? true : false);
24474 handleMouseDBClick : function(e, t){
24478 handleMouseDown : function(e, t)
24480 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24481 if(this.isLocked() || rowIndex < 0 ){
24484 if(e.shiftKey && this.last !== false){
24485 var last = this.last;
24486 this.selectRange(last, rowIndex, e.ctrlKey);
24487 this.last = last; // reset the last
24491 var isSelected = this.isSelected(rowIndex);
24492 //Roo.log("select row:" + rowIndex);
24494 this.deselectRow(rowIndex);
24496 this.selectRow(rowIndex, true);
24500 if(e.button !== 0 && isSelected){
24501 alert('rowIndex 2: ' + rowIndex);
24502 view.focusRow(rowIndex);
24503 }else if(e.ctrlKey && isSelected){
24504 this.deselectRow(rowIndex);
24505 }else if(!isSelected){
24506 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24507 view.focusRow(rowIndex);
24511 this.fireEvent("afterselectionchange", this);
24514 handleDragableRowClick : function(grid, rowIndex, e)
24516 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24517 this.selectRow(rowIndex, false);
24518 grid.view.focusRow(rowIndex);
24519 this.fireEvent("afterselectionchange", this);
24524 * Selects multiple rows.
24525 * @param {Array} rows Array of the indexes of the row to select
24526 * @param {Boolean} keepExisting (optional) True to keep existing selections
24528 selectRows : function(rows, keepExisting){
24530 this.clearSelections();
24532 for(var i = 0, len = rows.length; i < len; i++){
24533 this.selectRow(rows[i], true);
24538 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24539 * @param {Number} startRow The index of the first row in the range
24540 * @param {Number} endRow The index of the last row in the range
24541 * @param {Boolean} keepExisting (optional) True to retain existing selections
24543 selectRange : function(startRow, endRow, keepExisting){
24548 this.clearSelections();
24550 if(startRow <= endRow){
24551 for(var i = startRow; i <= endRow; i++){
24552 this.selectRow(i, true);
24555 for(var i = startRow; i >= endRow; i--){
24556 this.selectRow(i, true);
24562 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24563 * @param {Number} startRow The index of the first row in the range
24564 * @param {Number} endRow The index of the last row in the range
24566 deselectRange : function(startRow, endRow, preventViewNotify){
24570 for(var i = startRow; i <= endRow; i++){
24571 this.deselectRow(i, preventViewNotify);
24577 * @param {Number} row The index of the row to select
24578 * @param {Boolean} keepExisting (optional) True to keep existing selections
24580 selectRow : function(index, keepExisting, preventViewNotify)
24582 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24585 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24586 if(!keepExisting || this.singleSelect){
24587 this.clearSelections();
24590 var r = this.grid.store.getAt(index);
24591 //console.log('selectRow - record id :' + r.id);
24593 this.selections.add(r);
24594 this.last = this.lastActive = index;
24595 if(!preventViewNotify){
24596 var proxy = new Roo.Element(
24597 this.grid.getRowDom(index)
24599 proxy.addClass('bg-info info');
24601 this.fireEvent("rowselect", this, index, r);
24602 this.fireEvent("selectionchange", this);
24608 * @param {Number} row The index of the row to deselect
24610 deselectRow : function(index, preventViewNotify)
24615 if(this.last == index){
24618 if(this.lastActive == index){
24619 this.lastActive = false;
24622 var r = this.grid.store.getAt(index);
24627 this.selections.remove(r);
24628 //.console.log('deselectRow - record id :' + r.id);
24629 if(!preventViewNotify){
24631 var proxy = new Roo.Element(
24632 this.grid.getRowDom(index)
24634 proxy.removeClass('bg-info info');
24636 this.fireEvent("rowdeselect", this, index);
24637 this.fireEvent("selectionchange", this);
24641 restoreLast : function(){
24643 this.last = this._last;
24648 acceptsNav : function(row, col, cm){
24649 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24653 onEditorKey : function(field, e){
24654 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24659 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24661 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24663 }else if(k == e.ENTER && !e.ctrlKey){
24667 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24669 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24671 }else if(k == e.ESC){
24675 g.startEditing(newCell[0], newCell[1]);
24681 * Ext JS Library 1.1.1
24682 * Copyright(c) 2006-2007, Ext JS, LLC.
24684 * Originally Released Under LGPL - original licence link has changed is not relivant.
24687 * <script type="text/javascript">
24691 * @class Roo.bootstrap.PagingToolbar
24692 * @extends Roo.bootstrap.NavSimplebar
24693 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24695 * Create a new PagingToolbar
24696 * @param {Object} config The config object
24697 * @param {Roo.data.Store} store
24699 Roo.bootstrap.PagingToolbar = function(config)
24701 // old args format still supported... - xtype is prefered..
24702 // created from xtype...
24704 this.ds = config.dataSource;
24706 if (config.store && !this.ds) {
24707 this.store= Roo.factory(config.store, Roo.data);
24708 this.ds = this.store;
24709 this.ds.xmodule = this.xmodule || false;
24712 this.toolbarItems = [];
24713 if (config.items) {
24714 this.toolbarItems = config.items;
24717 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24722 this.bind(this.ds);
24725 if (Roo.bootstrap.version == 4) {
24726 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24728 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24733 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24735 * @cfg {Roo.data.Store} dataSource
24736 * The underlying data store providing the paged data
24739 * @cfg {String/HTMLElement/Element} container
24740 * container The id or element that will contain the toolbar
24743 * @cfg {Boolean} displayInfo
24744 * True to display the displayMsg (defaults to false)
24747 * @cfg {Number} pageSize
24748 * The number of records to display per page (defaults to 20)
24752 * @cfg {String} displayMsg
24753 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24755 displayMsg : 'Displaying {0} - {1} of {2}',
24757 * @cfg {String} emptyMsg
24758 * The message to display when no records are found (defaults to "No data to display")
24760 emptyMsg : 'No data to display',
24762 * Customizable piece of the default paging text (defaults to "Page")
24765 beforePageText : "Page",
24767 * Customizable piece of the default paging text (defaults to "of %0")
24770 afterPageText : "of {0}",
24772 * Customizable piece of the default paging text (defaults to "First Page")
24775 firstText : "First Page",
24777 * Customizable piece of the default paging text (defaults to "Previous Page")
24780 prevText : "Previous Page",
24782 * Customizable piece of the default paging text (defaults to "Next Page")
24785 nextText : "Next Page",
24787 * Customizable piece of the default paging text (defaults to "Last Page")
24790 lastText : "Last Page",
24792 * Customizable piece of the default paging text (defaults to "Refresh")
24795 refreshText : "Refresh",
24799 onRender : function(ct, position)
24801 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24802 this.navgroup.parentId = this.id;
24803 this.navgroup.onRender(this.el, null);
24804 // add the buttons to the navgroup
24806 if(this.displayInfo){
24807 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24808 this.displayEl = this.el.select('.x-paging-info', true).first();
24809 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24810 // this.displayEl = navel.el.select('span',true).first();
24816 Roo.each(_this.buttons, function(e){ // this might need to use render????
24817 Roo.factory(e).render(_this.el);
24821 Roo.each(_this.toolbarItems, function(e) {
24822 _this.navgroup.addItem(e);
24826 this.first = this.navgroup.addItem({
24827 tooltip: this.firstText,
24828 cls: "prev btn-outline-secondary",
24829 html : ' <i class="fa fa-step-backward"></i>',
24831 preventDefault: true,
24832 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24835 this.prev = this.navgroup.addItem({
24836 tooltip: this.prevText,
24837 cls: "prev btn-outline-secondary",
24838 html : ' <i class="fa fa-backward"></i>',
24840 preventDefault: true,
24841 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24843 //this.addSeparator();
24846 var field = this.navgroup.addItem( {
24848 cls : 'x-paging-position btn-outline-secondary',
24850 html : this.beforePageText +
24851 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24852 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24855 this.field = field.el.select('input', true).first();
24856 this.field.on("keydown", this.onPagingKeydown, this);
24857 this.field.on("focus", function(){this.dom.select();});
24860 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24861 //this.field.setHeight(18);
24862 //this.addSeparator();
24863 this.next = this.navgroup.addItem({
24864 tooltip: this.nextText,
24865 cls: "next btn-outline-secondary",
24866 html : ' <i class="fa fa-forward"></i>',
24868 preventDefault: true,
24869 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24871 this.last = this.navgroup.addItem({
24872 tooltip: this.lastText,
24873 html : ' <i class="fa fa-step-forward"></i>',
24874 cls: "next btn-outline-secondary",
24876 preventDefault: true,
24877 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24879 //this.addSeparator();
24880 this.loading = this.navgroup.addItem({
24881 tooltip: this.refreshText,
24882 cls: "btn-outline-secondary",
24883 html : ' <i class="fa fa-refresh"></i>',
24884 preventDefault: true,
24885 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24891 updateInfo : function(){
24892 if(this.displayEl){
24893 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24894 var msg = count == 0 ?
24898 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24900 this.displayEl.update(msg);
24905 onLoad : function(ds, r, o)
24907 this.cursor = o.params.start ? o.params.start : 0;
24909 var d = this.getPageData(),
24914 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24915 this.field.dom.value = ap;
24916 this.first.setDisabled(ap == 1);
24917 this.prev.setDisabled(ap == 1);
24918 this.next.setDisabled(ap == ps);
24919 this.last.setDisabled(ap == ps);
24920 this.loading.enable();
24925 getPageData : function(){
24926 var total = this.ds.getTotalCount();
24929 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24930 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24935 onLoadError : function(){
24936 this.loading.enable();
24940 onPagingKeydown : function(e){
24941 var k = e.getKey();
24942 var d = this.getPageData();
24944 var v = this.field.dom.value, pageNum;
24945 if(!v || isNaN(pageNum = parseInt(v, 10))){
24946 this.field.dom.value = d.activePage;
24949 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24950 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24953 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))
24955 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24956 this.field.dom.value = pageNum;
24957 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24960 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24962 var v = this.field.dom.value, pageNum;
24963 var increment = (e.shiftKey) ? 10 : 1;
24964 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24967 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24968 this.field.dom.value = d.activePage;
24971 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24973 this.field.dom.value = parseInt(v, 10) + increment;
24974 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24975 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24982 beforeLoad : function(){
24984 this.loading.disable();
24989 onClick : function(which){
24998 ds.load({params:{start: 0, limit: this.pageSize}});
25001 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25004 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25007 var total = ds.getTotalCount();
25008 var extra = total % this.pageSize;
25009 var lastStart = extra ? (total - extra) : total-this.pageSize;
25010 ds.load({params:{start: lastStart, limit: this.pageSize}});
25013 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25019 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25020 * @param {Roo.data.Store} store The data store to unbind
25022 unbind : function(ds){
25023 ds.un("beforeload", this.beforeLoad, this);
25024 ds.un("load", this.onLoad, this);
25025 ds.un("loadexception", this.onLoadError, this);
25026 ds.un("remove", this.updateInfo, this);
25027 ds.un("add", this.updateInfo, this);
25028 this.ds = undefined;
25032 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25033 * @param {Roo.data.Store} store The data store to bind
25035 bind : function(ds){
25036 ds.on("beforeload", this.beforeLoad, this);
25037 ds.on("load", this.onLoad, this);
25038 ds.on("loadexception", this.onLoadError, this);
25039 ds.on("remove", this.updateInfo, this);
25040 ds.on("add", this.updateInfo, this);
25051 * @class Roo.bootstrap.MessageBar
25052 * @extends Roo.bootstrap.Component
25053 * Bootstrap MessageBar class
25054 * @cfg {String} html contents of the MessageBar
25055 * @cfg {String} weight (info | success | warning | danger) default info
25056 * @cfg {String} beforeClass insert the bar before the given class
25057 * @cfg {Boolean} closable (true | false) default false
25058 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25061 * Create a new Element
25062 * @param {Object} config The config object
25065 Roo.bootstrap.MessageBar = function(config){
25066 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25069 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25075 beforeClass: 'bootstrap-sticky-wrap',
25077 getAutoCreate : function(){
25081 cls: 'alert alert-dismissable alert-' + this.weight,
25086 html: this.html || ''
25092 cfg.cls += ' alert-messages-fixed';
25106 onRender : function(ct, position)
25108 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25111 var cfg = Roo.apply({}, this.getAutoCreate());
25115 cfg.cls += ' ' + this.cls;
25118 cfg.style = this.style;
25120 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25122 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25125 this.el.select('>button.close').on('click', this.hide, this);
25131 if (!this.rendered) {
25137 this.fireEvent('show', this);
25143 if (!this.rendered) {
25149 this.fireEvent('hide', this);
25152 update : function()
25154 // var e = this.el.dom.firstChild;
25156 // if(this.closable){
25157 // e = e.nextSibling;
25160 // e.data = this.html || '';
25162 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25178 * @class Roo.bootstrap.Graph
25179 * @extends Roo.bootstrap.Component
25180 * Bootstrap Graph class
25184 @cfg {String} graphtype bar | vbar | pie
25185 @cfg {number} g_x coodinator | centre x (pie)
25186 @cfg {number} g_y coodinator | centre y (pie)
25187 @cfg {number} g_r radius (pie)
25188 @cfg {number} g_height height of the chart (respected by all elements in the set)
25189 @cfg {number} g_width width of the chart (respected by all elements in the set)
25190 @cfg {Object} title The title of the chart
25193 -opts (object) options for the chart
25195 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25196 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25198 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.
25199 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25201 o stretch (boolean)
25203 -opts (object) options for the pie
25206 o startAngle (number)
25207 o endAngle (number)
25211 * Create a new Input
25212 * @param {Object} config The config object
25215 Roo.bootstrap.Graph = function(config){
25216 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25222 * The img click event for the img.
25223 * @param {Roo.EventObject} e
25229 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25240 //g_colors: this.colors,
25247 getAutoCreate : function(){
25258 onRender : function(ct,position){
25261 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25263 if (typeof(Raphael) == 'undefined') {
25264 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25268 this.raphael = Raphael(this.el.dom);
25270 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25271 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25272 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25273 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25275 r.text(160, 10, "Single Series Chart").attr(txtattr);
25276 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25277 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25278 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25280 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25281 r.barchart(330, 10, 300, 220, data1);
25282 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25283 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25286 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25287 // r.barchart(30, 30, 560, 250, xdata, {
25288 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25289 // axis : "0 0 1 1",
25290 // axisxlabels : xdata
25291 // //yvalues : cols,
25294 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25296 // this.load(null,xdata,{
25297 // axis : "0 0 1 1",
25298 // axisxlabels : xdata
25303 load : function(graphtype,xdata,opts)
25305 this.raphael.clear();
25307 graphtype = this.graphtype;
25312 var r = this.raphael,
25313 fin = function () {
25314 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25316 fout = function () {
25317 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25319 pfin = function() {
25320 this.sector.stop();
25321 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25324 this.label[0].stop();
25325 this.label[0].attr({ r: 7.5 });
25326 this.label[1].attr({ "font-weight": 800 });
25329 pfout = function() {
25330 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25333 this.label[0].animate({ r: 5 }, 500, "bounce");
25334 this.label[1].attr({ "font-weight": 400 });
25340 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25343 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25346 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25347 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25349 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25356 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25361 setTitle: function(o)
25366 initEvents: function() {
25369 this.el.on('click', this.onClick, this);
25373 onClick : function(e)
25375 Roo.log('img onclick');
25376 this.fireEvent('click', this, e);
25388 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25391 * @class Roo.bootstrap.dash.NumberBox
25392 * @extends Roo.bootstrap.Component
25393 * Bootstrap NumberBox class
25394 * @cfg {String} headline Box headline
25395 * @cfg {String} content Box content
25396 * @cfg {String} icon Box icon
25397 * @cfg {String} footer Footer text
25398 * @cfg {String} fhref Footer href
25401 * Create a new NumberBox
25402 * @param {Object} config The config object
25406 Roo.bootstrap.dash.NumberBox = function(config){
25407 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25411 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25420 getAutoCreate : function(){
25424 cls : 'small-box ',
25432 cls : 'roo-headline',
25433 html : this.headline
25437 cls : 'roo-content',
25438 html : this.content
25452 cls : 'ion ' + this.icon
25461 cls : 'small-box-footer',
25462 href : this.fhref || '#',
25466 cfg.cn.push(footer);
25473 onRender : function(ct,position){
25474 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25481 setHeadline: function (value)
25483 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25486 setFooter: function (value, href)
25488 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25491 this.el.select('a.small-box-footer',true).first().attr('href', href);
25496 setContent: function (value)
25498 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25501 initEvents: function()
25515 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25518 * @class Roo.bootstrap.dash.TabBox
25519 * @extends Roo.bootstrap.Component
25520 * Bootstrap TabBox class
25521 * @cfg {String} title Title of the TabBox
25522 * @cfg {String} icon Icon of the TabBox
25523 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25524 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25527 * Create a new TabBox
25528 * @param {Object} config The config object
25532 Roo.bootstrap.dash.TabBox = function(config){
25533 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25538 * When a pane is added
25539 * @param {Roo.bootstrap.dash.TabPane} pane
25543 * @event activatepane
25544 * When a pane is activated
25545 * @param {Roo.bootstrap.dash.TabPane} pane
25547 "activatepane" : true
25555 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25560 tabScrollable : false,
25562 getChildContainer : function()
25564 return this.el.select('.tab-content', true).first();
25567 getAutoCreate : function(){
25571 cls: 'pull-left header',
25579 cls: 'fa ' + this.icon
25585 cls: 'nav nav-tabs pull-right',
25591 if(this.tabScrollable){
25598 cls: 'nav nav-tabs pull-right',
25609 cls: 'nav-tabs-custom',
25614 cls: 'tab-content no-padding',
25622 initEvents : function()
25624 //Roo.log('add add pane handler');
25625 this.on('addpane', this.onAddPane, this);
25628 * Updates the box title
25629 * @param {String} html to set the title to.
25631 setTitle : function(value)
25633 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25635 onAddPane : function(pane)
25637 this.panes.push(pane);
25638 //Roo.log('addpane');
25640 // tabs are rendere left to right..
25641 if(!this.showtabs){
25645 var ctr = this.el.select('.nav-tabs', true).first();
25648 var existing = ctr.select('.nav-tab',true);
25649 var qty = existing.getCount();;
25652 var tab = ctr.createChild({
25654 cls : 'nav-tab' + (qty ? '' : ' active'),
25662 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25665 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25667 pane.el.addClass('active');
25672 onTabClick : function(ev,un,ob,pane)
25674 //Roo.log('tab - prev default');
25675 ev.preventDefault();
25678 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25679 pane.tab.addClass('active');
25680 //Roo.log(pane.title);
25681 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25682 // technically we should have a deactivate event.. but maybe add later.
25683 // and it should not de-activate the selected tab...
25684 this.fireEvent('activatepane', pane);
25685 pane.el.addClass('active');
25686 pane.fireEvent('activate');
25691 getActivePane : function()
25694 Roo.each(this.panes, function(p) {
25695 if(p.el.hasClass('active')){
25716 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25718 * @class Roo.bootstrap.TabPane
25719 * @extends Roo.bootstrap.Component
25720 * Bootstrap TabPane class
25721 * @cfg {Boolean} active (false | true) Default false
25722 * @cfg {String} title title of panel
25726 * Create a new TabPane
25727 * @param {Object} config The config object
25730 Roo.bootstrap.dash.TabPane = function(config){
25731 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25737 * When a pane is activated
25738 * @param {Roo.bootstrap.dash.TabPane} pane
25745 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25750 // the tabBox that this is attached to.
25753 getAutoCreate : function()
25761 cfg.cls += ' active';
25766 initEvents : function()
25768 //Roo.log('trigger add pane handler');
25769 this.parent().fireEvent('addpane', this)
25773 * Updates the tab title
25774 * @param {String} html to set the title to.
25776 setTitle: function(str)
25782 this.tab.select('a', true).first().dom.innerHTML = str;
25799 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25802 * @class Roo.bootstrap.menu.Menu
25803 * @extends Roo.bootstrap.Component
25804 * Bootstrap Menu class - container for Menu
25805 * @cfg {String} html Text of the menu
25806 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25807 * @cfg {String} icon Font awesome icon
25808 * @cfg {String} pos Menu align to (top | bottom) default bottom
25812 * Create a new Menu
25813 * @param {Object} config The config object
25817 Roo.bootstrap.menu.Menu = function(config){
25818 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25822 * @event beforeshow
25823 * Fires before this menu is displayed
25824 * @param {Roo.bootstrap.menu.Menu} this
25828 * @event beforehide
25829 * Fires before this menu is hidden
25830 * @param {Roo.bootstrap.menu.Menu} this
25835 * Fires after this menu is displayed
25836 * @param {Roo.bootstrap.menu.Menu} this
25841 * Fires after this menu is hidden
25842 * @param {Roo.bootstrap.menu.Menu} this
25847 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25848 * @param {Roo.bootstrap.menu.Menu} this
25849 * @param {Roo.EventObject} e
25856 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25860 weight : 'default',
25865 getChildContainer : function() {
25866 if(this.isSubMenu){
25870 return this.el.select('ul.dropdown-menu', true).first();
25873 getAutoCreate : function()
25878 cls : 'roo-menu-text',
25886 cls : 'fa ' + this.icon
25897 cls : 'dropdown-button btn btn-' + this.weight,
25902 cls : 'dropdown-toggle btn btn-' + this.weight,
25912 cls : 'dropdown-menu'
25918 if(this.pos == 'top'){
25919 cfg.cls += ' dropup';
25922 if(this.isSubMenu){
25925 cls : 'dropdown-menu'
25932 onRender : function(ct, position)
25934 this.isSubMenu = ct.hasClass('dropdown-submenu');
25936 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25939 initEvents : function()
25941 if(this.isSubMenu){
25945 this.hidden = true;
25947 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25948 this.triggerEl.on('click', this.onTriggerPress, this);
25950 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25951 this.buttonEl.on('click', this.onClick, this);
25957 if(this.isSubMenu){
25961 return this.el.select('ul.dropdown-menu', true).first();
25964 onClick : function(e)
25966 this.fireEvent("click", this, e);
25969 onTriggerPress : function(e)
25971 if (this.isVisible()) {
25978 isVisible : function(){
25979 return !this.hidden;
25984 this.fireEvent("beforeshow", this);
25986 this.hidden = false;
25987 this.el.addClass('open');
25989 Roo.get(document).on("mouseup", this.onMouseUp, this);
25991 this.fireEvent("show", this);
25998 this.fireEvent("beforehide", this);
26000 this.hidden = true;
26001 this.el.removeClass('open');
26003 Roo.get(document).un("mouseup", this.onMouseUp);
26005 this.fireEvent("hide", this);
26008 onMouseUp : function()
26022 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26025 * @class Roo.bootstrap.menu.Item
26026 * @extends Roo.bootstrap.Component
26027 * Bootstrap MenuItem class
26028 * @cfg {Boolean} submenu (true | false) default false
26029 * @cfg {String} html text of the item
26030 * @cfg {String} href the link
26031 * @cfg {Boolean} disable (true | false) default false
26032 * @cfg {Boolean} preventDefault (true | false) default true
26033 * @cfg {String} icon Font awesome icon
26034 * @cfg {String} pos Submenu align to (left | right) default right
26038 * Create a new Item
26039 * @param {Object} config The config object
26043 Roo.bootstrap.menu.Item = function(config){
26044 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26048 * Fires when the mouse is hovering over this menu
26049 * @param {Roo.bootstrap.menu.Item} this
26050 * @param {Roo.EventObject} e
26055 * Fires when the mouse exits this menu
26056 * @param {Roo.bootstrap.menu.Item} this
26057 * @param {Roo.EventObject} e
26063 * The raw click event for the entire grid.
26064 * @param {Roo.EventObject} e
26070 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26075 preventDefault: true,
26080 getAutoCreate : function()
26085 cls : 'roo-menu-item-text',
26093 cls : 'fa ' + this.icon
26102 href : this.href || '#',
26109 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26113 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26115 if(this.pos == 'left'){
26116 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26123 initEvents : function()
26125 this.el.on('mouseover', this.onMouseOver, this);
26126 this.el.on('mouseout', this.onMouseOut, this);
26128 this.el.select('a', true).first().on('click', this.onClick, this);
26132 onClick : function(e)
26134 if(this.preventDefault){
26135 e.preventDefault();
26138 this.fireEvent("click", this, e);
26141 onMouseOver : function(e)
26143 if(this.submenu && this.pos == 'left'){
26144 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26147 this.fireEvent("mouseover", this, e);
26150 onMouseOut : function(e)
26152 this.fireEvent("mouseout", this, e);
26164 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26167 * @class Roo.bootstrap.menu.Separator
26168 * @extends Roo.bootstrap.Component
26169 * Bootstrap Separator class
26172 * Create a new Separator
26173 * @param {Object} config The config object
26177 Roo.bootstrap.menu.Separator = function(config){
26178 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26181 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26183 getAutoCreate : function(){
26204 * @class Roo.bootstrap.Tooltip
26205 * Bootstrap Tooltip class
26206 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26207 * to determine which dom element triggers the tooltip.
26209 * It needs to add support for additional attributes like tooltip-position
26212 * Create a new Toolti
26213 * @param {Object} config The config object
26216 Roo.bootstrap.Tooltip = function(config){
26217 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26219 this.alignment = Roo.bootstrap.Tooltip.alignment;
26221 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26222 this.alignment = config.alignment;
26227 Roo.apply(Roo.bootstrap.Tooltip, {
26229 * @function init initialize tooltip monitoring.
26233 currentTip : false,
26234 currentRegion : false,
26240 Roo.get(document).on('mouseover', this.enter ,this);
26241 Roo.get(document).on('mouseout', this.leave, this);
26244 this.currentTip = new Roo.bootstrap.Tooltip();
26247 enter : function(ev)
26249 var dom = ev.getTarget();
26251 //Roo.log(['enter',dom]);
26252 var el = Roo.fly(dom);
26253 if (this.currentEl) {
26255 //Roo.log(this.currentEl);
26256 //Roo.log(this.currentEl.contains(dom));
26257 if (this.currentEl == el) {
26260 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26266 if (this.currentTip.el) {
26267 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26271 if(!el || el.dom == document){
26277 // you can not look for children, as if el is the body.. then everythign is the child..
26278 if (!el.attr('tooltip')) { //
26279 if (!el.select("[tooltip]").elements.length) {
26282 // is the mouse over this child...?
26283 bindEl = el.select("[tooltip]").first();
26284 var xy = ev.getXY();
26285 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26286 //Roo.log("not in region.");
26289 //Roo.log("child element over..");
26292 this.currentEl = bindEl;
26293 this.currentTip.bind(bindEl);
26294 this.currentRegion = Roo.lib.Region.getRegion(dom);
26295 this.currentTip.enter();
26298 leave : function(ev)
26300 var dom = ev.getTarget();
26301 //Roo.log(['leave',dom]);
26302 if (!this.currentEl) {
26307 if (dom != this.currentEl.dom) {
26310 var xy = ev.getXY();
26311 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26314 // only activate leave if mouse cursor is outside... bounding box..
26319 if (this.currentTip) {
26320 this.currentTip.leave();
26322 //Roo.log('clear currentEl');
26323 this.currentEl = false;
26328 'left' : ['r-l', [-2,0], 'right'],
26329 'right' : ['l-r', [2,0], 'left'],
26330 'bottom' : ['t-b', [0,2], 'top'],
26331 'top' : [ 'b-t', [0,-2], 'bottom']
26337 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26342 delay : null, // can be { show : 300 , hide: 500}
26346 hoverState : null, //???
26348 placement : 'bottom',
26352 getAutoCreate : function(){
26359 cls : 'tooltip-arrow'
26362 cls : 'tooltip-inner'
26369 bind : function(el)
26375 enter : function () {
26377 if (this.timeout != null) {
26378 clearTimeout(this.timeout);
26381 this.hoverState = 'in';
26382 //Roo.log("enter - show");
26383 if (!this.delay || !this.delay.show) {
26388 this.timeout = setTimeout(function () {
26389 if (_t.hoverState == 'in') {
26392 }, this.delay.show);
26396 clearTimeout(this.timeout);
26398 this.hoverState = 'out';
26399 if (!this.delay || !this.delay.hide) {
26405 this.timeout = setTimeout(function () {
26406 //Roo.log("leave - timeout");
26408 if (_t.hoverState == 'out') {
26410 Roo.bootstrap.Tooltip.currentEl = false;
26415 show : function (msg)
26418 this.render(document.body);
26421 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26423 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26425 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26427 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26429 var placement = typeof this.placement == 'function' ?
26430 this.placement.call(this, this.el, on_el) :
26433 var autoToken = /\s?auto?\s?/i;
26434 var autoPlace = autoToken.test(placement);
26436 placement = placement.replace(autoToken, '') || 'top';
26440 //this.el.setXY([0,0]);
26442 //this.el.dom.style.display='block';
26444 //this.el.appendTo(on_el);
26446 var p = this.getPosition();
26447 var box = this.el.getBox();
26453 var align = this.alignment[placement];
26455 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26457 if(placement == 'top' || placement == 'bottom'){
26459 placement = 'right';
26462 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26463 placement = 'left';
26466 var scroll = Roo.select('body', true).first().getScroll();
26468 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26472 align = this.alignment[placement];
26475 this.el.alignTo(this.bindEl, align[0],align[1]);
26476 //var arrow = this.el.select('.arrow',true).first();
26477 //arrow.set(align[2],
26479 this.el.addClass(placement);
26481 this.el.addClass('in fade');
26483 this.hoverState = null;
26485 if (this.el.hasClass('fade')) {
26496 //this.el.setXY([0,0]);
26497 this.el.removeClass('in');
26513 * @class Roo.bootstrap.LocationPicker
26514 * @extends Roo.bootstrap.Component
26515 * Bootstrap LocationPicker class
26516 * @cfg {Number} latitude Position when init default 0
26517 * @cfg {Number} longitude Position when init default 0
26518 * @cfg {Number} zoom default 15
26519 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26520 * @cfg {Boolean} mapTypeControl default false
26521 * @cfg {Boolean} disableDoubleClickZoom default false
26522 * @cfg {Boolean} scrollwheel default true
26523 * @cfg {Boolean} streetViewControl default false
26524 * @cfg {Number} radius default 0
26525 * @cfg {String} locationName
26526 * @cfg {Boolean} draggable default true
26527 * @cfg {Boolean} enableAutocomplete default false
26528 * @cfg {Boolean} enableReverseGeocode default true
26529 * @cfg {String} markerTitle
26532 * Create a new LocationPicker
26533 * @param {Object} config The config object
26537 Roo.bootstrap.LocationPicker = function(config){
26539 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26544 * Fires when the picker initialized.
26545 * @param {Roo.bootstrap.LocationPicker} this
26546 * @param {Google Location} location
26550 * @event positionchanged
26551 * Fires when the picker position changed.
26552 * @param {Roo.bootstrap.LocationPicker} this
26553 * @param {Google Location} location
26555 positionchanged : true,
26558 * Fires when the map resize.
26559 * @param {Roo.bootstrap.LocationPicker} this
26564 * Fires when the map show.
26565 * @param {Roo.bootstrap.LocationPicker} this
26570 * Fires when the map hide.
26571 * @param {Roo.bootstrap.LocationPicker} this
26576 * Fires when click the map.
26577 * @param {Roo.bootstrap.LocationPicker} this
26578 * @param {Map event} e
26582 * @event mapRightClick
26583 * Fires when right click the map.
26584 * @param {Roo.bootstrap.LocationPicker} this
26585 * @param {Map event} e
26587 mapRightClick : true,
26589 * @event markerClick
26590 * Fires when click the marker.
26591 * @param {Roo.bootstrap.LocationPicker} this
26592 * @param {Map event} e
26594 markerClick : true,
26596 * @event markerRightClick
26597 * Fires when right click the marker.
26598 * @param {Roo.bootstrap.LocationPicker} this
26599 * @param {Map event} e
26601 markerRightClick : true,
26603 * @event OverlayViewDraw
26604 * Fires when OverlayView Draw
26605 * @param {Roo.bootstrap.LocationPicker} this
26607 OverlayViewDraw : true,
26609 * @event OverlayViewOnAdd
26610 * Fires when OverlayView Draw
26611 * @param {Roo.bootstrap.LocationPicker} this
26613 OverlayViewOnAdd : true,
26615 * @event OverlayViewOnRemove
26616 * Fires when OverlayView Draw
26617 * @param {Roo.bootstrap.LocationPicker} this
26619 OverlayViewOnRemove : true,
26621 * @event OverlayViewShow
26622 * Fires when OverlayView Draw
26623 * @param {Roo.bootstrap.LocationPicker} this
26624 * @param {Pixel} cpx
26626 OverlayViewShow : true,
26628 * @event OverlayViewHide
26629 * Fires when OverlayView Draw
26630 * @param {Roo.bootstrap.LocationPicker} this
26632 OverlayViewHide : true,
26634 * @event loadexception
26635 * Fires when load google lib failed.
26636 * @param {Roo.bootstrap.LocationPicker} this
26638 loadexception : true
26643 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26645 gMapContext: false,
26651 mapTypeControl: false,
26652 disableDoubleClickZoom: false,
26654 streetViewControl: false,
26658 enableAutocomplete: false,
26659 enableReverseGeocode: true,
26662 getAutoCreate: function()
26667 cls: 'roo-location-picker'
26673 initEvents: function(ct, position)
26675 if(!this.el.getWidth() || this.isApplied()){
26679 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26684 initial: function()
26686 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26687 this.fireEvent('loadexception', this);
26691 if(!this.mapTypeId){
26692 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26695 this.gMapContext = this.GMapContext();
26697 this.initOverlayView();
26699 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26703 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26704 _this.setPosition(_this.gMapContext.marker.position);
26707 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26708 _this.fireEvent('mapClick', this, event);
26712 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26713 _this.fireEvent('mapRightClick', this, event);
26717 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26718 _this.fireEvent('markerClick', this, event);
26722 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26723 _this.fireEvent('markerRightClick', this, event);
26727 this.setPosition(this.gMapContext.location);
26729 this.fireEvent('initial', this, this.gMapContext.location);
26732 initOverlayView: function()
26736 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26740 _this.fireEvent('OverlayViewDraw', _this);
26745 _this.fireEvent('OverlayViewOnAdd', _this);
26748 onRemove: function()
26750 _this.fireEvent('OverlayViewOnRemove', _this);
26753 show: function(cpx)
26755 _this.fireEvent('OverlayViewShow', _this, cpx);
26760 _this.fireEvent('OverlayViewHide', _this);
26766 fromLatLngToContainerPixel: function(event)
26768 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26771 isApplied: function()
26773 return this.getGmapContext() == false ? false : true;
26776 getGmapContext: function()
26778 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26781 GMapContext: function()
26783 var position = new google.maps.LatLng(this.latitude, this.longitude);
26785 var _map = new google.maps.Map(this.el.dom, {
26788 mapTypeId: this.mapTypeId,
26789 mapTypeControl: this.mapTypeControl,
26790 disableDoubleClickZoom: this.disableDoubleClickZoom,
26791 scrollwheel: this.scrollwheel,
26792 streetViewControl: this.streetViewControl,
26793 locationName: this.locationName,
26794 draggable: this.draggable,
26795 enableAutocomplete: this.enableAutocomplete,
26796 enableReverseGeocode: this.enableReverseGeocode
26799 var _marker = new google.maps.Marker({
26800 position: position,
26802 title: this.markerTitle,
26803 draggable: this.draggable
26810 location: position,
26811 radius: this.radius,
26812 locationName: this.locationName,
26813 addressComponents: {
26814 formatted_address: null,
26815 addressLine1: null,
26816 addressLine2: null,
26818 streetNumber: null,
26822 stateOrProvince: null
26825 domContainer: this.el.dom,
26826 geodecoder: new google.maps.Geocoder()
26830 drawCircle: function(center, radius, options)
26832 if (this.gMapContext.circle != null) {
26833 this.gMapContext.circle.setMap(null);
26837 options = Roo.apply({}, options, {
26838 strokeColor: "#0000FF",
26839 strokeOpacity: .35,
26841 fillColor: "#0000FF",
26845 options.map = this.gMapContext.map;
26846 options.radius = radius;
26847 options.center = center;
26848 this.gMapContext.circle = new google.maps.Circle(options);
26849 return this.gMapContext.circle;
26855 setPosition: function(location)
26857 this.gMapContext.location = location;
26858 this.gMapContext.marker.setPosition(location);
26859 this.gMapContext.map.panTo(location);
26860 this.drawCircle(location, this.gMapContext.radius, {});
26864 if (this.gMapContext.settings.enableReverseGeocode) {
26865 this.gMapContext.geodecoder.geocode({
26866 latLng: this.gMapContext.location
26867 }, function(results, status) {
26869 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26870 _this.gMapContext.locationName = results[0].formatted_address;
26871 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26873 _this.fireEvent('positionchanged', this, location);
26880 this.fireEvent('positionchanged', this, location);
26885 google.maps.event.trigger(this.gMapContext.map, "resize");
26887 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26889 this.fireEvent('resize', this);
26892 setPositionByLatLng: function(latitude, longitude)
26894 this.setPosition(new google.maps.LatLng(latitude, longitude));
26897 getCurrentPosition: function()
26900 latitude: this.gMapContext.location.lat(),
26901 longitude: this.gMapContext.location.lng()
26905 getAddressName: function()
26907 return this.gMapContext.locationName;
26910 getAddressComponents: function()
26912 return this.gMapContext.addressComponents;
26915 address_component_from_google_geocode: function(address_components)
26919 for (var i = 0; i < address_components.length; i++) {
26920 var component = address_components[i];
26921 if (component.types.indexOf("postal_code") >= 0) {
26922 result.postalCode = component.short_name;
26923 } else if (component.types.indexOf("street_number") >= 0) {
26924 result.streetNumber = component.short_name;
26925 } else if (component.types.indexOf("route") >= 0) {
26926 result.streetName = component.short_name;
26927 } else if (component.types.indexOf("neighborhood") >= 0) {
26928 result.city = component.short_name;
26929 } else if (component.types.indexOf("locality") >= 0) {
26930 result.city = component.short_name;
26931 } else if (component.types.indexOf("sublocality") >= 0) {
26932 result.district = component.short_name;
26933 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26934 result.stateOrProvince = component.short_name;
26935 } else if (component.types.indexOf("country") >= 0) {
26936 result.country = component.short_name;
26940 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26941 result.addressLine2 = "";
26945 setZoomLevel: function(zoom)
26947 this.gMapContext.map.setZoom(zoom);
26960 this.fireEvent('show', this);
26971 this.fireEvent('hide', this);
26976 Roo.apply(Roo.bootstrap.LocationPicker, {
26978 OverlayView : function(map, options)
26980 options = options || {};
26994 * @class Roo.bootstrap.Alert
26995 * @extends Roo.bootstrap.Component
26996 * Bootstrap Alert class
26997 * @cfg {String} title The title of alert
26998 * @cfg {String} html The content of alert
26999 * @cfg {String} weight ( success | info | warning | danger )
27000 * @cfg {String} faicon font-awesomeicon
27003 * Create a new alert
27004 * @param {Object} config The config object
27008 Roo.bootstrap.Alert = function(config){
27009 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27013 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27020 getAutoCreate : function()
27029 cls : 'roo-alert-icon'
27034 cls : 'roo-alert-title',
27039 cls : 'roo-alert-text',
27046 cfg.cn[0].cls += ' fa ' + this.faicon;
27050 cfg.cls += ' alert-' + this.weight;
27056 initEvents: function()
27058 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27061 setTitle : function(str)
27063 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27066 setText : function(str)
27068 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27071 setWeight : function(weight)
27074 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27077 this.weight = weight;
27079 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27082 setIcon : function(icon)
27085 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27088 this.faicon = icon;
27090 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27111 * @class Roo.bootstrap.UploadCropbox
27112 * @extends Roo.bootstrap.Component
27113 * Bootstrap UploadCropbox class
27114 * @cfg {String} emptyText show when image has been loaded
27115 * @cfg {String} rotateNotify show when image too small to rotate
27116 * @cfg {Number} errorTimeout default 3000
27117 * @cfg {Number} minWidth default 300
27118 * @cfg {Number} minHeight default 300
27119 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27120 * @cfg {Boolean} isDocument (true|false) default false
27121 * @cfg {String} url action url
27122 * @cfg {String} paramName default 'imageUpload'
27123 * @cfg {String} method default POST
27124 * @cfg {Boolean} loadMask (true|false) default true
27125 * @cfg {Boolean} loadingText default 'Loading...'
27128 * Create a new UploadCropbox
27129 * @param {Object} config The config object
27132 Roo.bootstrap.UploadCropbox = function(config){
27133 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27137 * @event beforeselectfile
27138 * Fire before select file
27139 * @param {Roo.bootstrap.UploadCropbox} this
27141 "beforeselectfile" : true,
27144 * Fire after initEvent
27145 * @param {Roo.bootstrap.UploadCropbox} this
27150 * Fire after initEvent
27151 * @param {Roo.bootstrap.UploadCropbox} this
27152 * @param {String} data
27157 * Fire when preparing the file data
27158 * @param {Roo.bootstrap.UploadCropbox} this
27159 * @param {Object} file
27164 * Fire when get exception
27165 * @param {Roo.bootstrap.UploadCropbox} this
27166 * @param {XMLHttpRequest} xhr
27168 "exception" : true,
27170 * @event beforeloadcanvas
27171 * Fire before load the canvas
27172 * @param {Roo.bootstrap.UploadCropbox} this
27173 * @param {String} src
27175 "beforeloadcanvas" : true,
27178 * Fire when trash image
27179 * @param {Roo.bootstrap.UploadCropbox} this
27184 * Fire when download the image
27185 * @param {Roo.bootstrap.UploadCropbox} this
27189 * @event footerbuttonclick
27190 * Fire when footerbuttonclick
27191 * @param {Roo.bootstrap.UploadCropbox} this
27192 * @param {String} type
27194 "footerbuttonclick" : true,
27198 * @param {Roo.bootstrap.UploadCropbox} this
27203 * Fire when rotate the image
27204 * @param {Roo.bootstrap.UploadCropbox} this
27205 * @param {String} pos
27210 * Fire when inspect the file
27211 * @param {Roo.bootstrap.UploadCropbox} this
27212 * @param {Object} file
27217 * Fire when xhr upload the file
27218 * @param {Roo.bootstrap.UploadCropbox} this
27219 * @param {Object} data
27224 * Fire when arrange the file data
27225 * @param {Roo.bootstrap.UploadCropbox} this
27226 * @param {Object} formData
27231 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27234 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27236 emptyText : 'Click to upload image',
27237 rotateNotify : 'Image is too small to rotate',
27238 errorTimeout : 3000,
27252 cropType : 'image/jpeg',
27254 canvasLoaded : false,
27255 isDocument : false,
27257 paramName : 'imageUpload',
27259 loadingText : 'Loading...',
27262 getAutoCreate : function()
27266 cls : 'roo-upload-cropbox',
27270 cls : 'roo-upload-cropbox-selector',
27275 cls : 'roo-upload-cropbox-body',
27276 style : 'cursor:pointer',
27280 cls : 'roo-upload-cropbox-preview'
27284 cls : 'roo-upload-cropbox-thumb'
27288 cls : 'roo-upload-cropbox-empty-notify',
27289 html : this.emptyText
27293 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27294 html : this.rotateNotify
27300 cls : 'roo-upload-cropbox-footer',
27303 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27313 onRender : function(ct, position)
27315 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27317 if (this.buttons.length) {
27319 Roo.each(this.buttons, function(bb) {
27321 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27323 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27329 this.maskEl = this.el;
27333 initEvents : function()
27335 this.urlAPI = (window.createObjectURL && window) ||
27336 (window.URL && URL.revokeObjectURL && URL) ||
27337 (window.webkitURL && webkitURL);
27339 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27340 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27342 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27343 this.selectorEl.hide();
27345 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27346 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27348 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27349 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27350 this.thumbEl.hide();
27352 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27353 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27355 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27356 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27357 this.errorEl.hide();
27359 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27360 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27361 this.footerEl.hide();
27363 this.setThumbBoxSize();
27369 this.fireEvent('initial', this);
27376 window.addEventListener("resize", function() { _this.resize(); } );
27378 this.bodyEl.on('click', this.beforeSelectFile, this);
27381 this.bodyEl.on('touchstart', this.onTouchStart, this);
27382 this.bodyEl.on('touchmove', this.onTouchMove, this);
27383 this.bodyEl.on('touchend', this.onTouchEnd, this);
27387 this.bodyEl.on('mousedown', this.onMouseDown, this);
27388 this.bodyEl.on('mousemove', this.onMouseMove, this);
27389 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27390 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27391 Roo.get(document).on('mouseup', this.onMouseUp, this);
27394 this.selectorEl.on('change', this.onFileSelected, this);
27400 this.baseScale = 1;
27402 this.baseRotate = 1;
27403 this.dragable = false;
27404 this.pinching = false;
27407 this.cropData = false;
27408 this.notifyEl.dom.innerHTML = this.emptyText;
27410 this.selectorEl.dom.value = '';
27414 resize : function()
27416 if(this.fireEvent('resize', this) != false){
27417 this.setThumbBoxPosition();
27418 this.setCanvasPosition();
27422 onFooterButtonClick : function(e, el, o, type)
27425 case 'rotate-left' :
27426 this.onRotateLeft(e);
27428 case 'rotate-right' :
27429 this.onRotateRight(e);
27432 this.beforeSelectFile(e);
27447 this.fireEvent('footerbuttonclick', this, type);
27450 beforeSelectFile : function(e)
27452 e.preventDefault();
27454 if(this.fireEvent('beforeselectfile', this) != false){
27455 this.selectorEl.dom.click();
27459 onFileSelected : function(e)
27461 e.preventDefault();
27463 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27467 var file = this.selectorEl.dom.files[0];
27469 if(this.fireEvent('inspect', this, file) != false){
27470 this.prepare(file);
27475 trash : function(e)
27477 this.fireEvent('trash', this);
27480 download : function(e)
27482 this.fireEvent('download', this);
27485 loadCanvas : function(src)
27487 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27491 this.imageEl = document.createElement('img');
27495 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27497 this.imageEl.src = src;
27501 onLoadCanvas : function()
27503 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27504 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27506 this.bodyEl.un('click', this.beforeSelectFile, this);
27508 this.notifyEl.hide();
27509 this.thumbEl.show();
27510 this.footerEl.show();
27512 this.baseRotateLevel();
27514 if(this.isDocument){
27515 this.setThumbBoxSize();
27518 this.setThumbBoxPosition();
27520 this.baseScaleLevel();
27526 this.canvasLoaded = true;
27529 this.maskEl.unmask();
27534 setCanvasPosition : function()
27536 if(!this.canvasEl){
27540 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27541 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27543 this.previewEl.setLeft(pw);
27544 this.previewEl.setTop(ph);
27548 onMouseDown : function(e)
27552 this.dragable = true;
27553 this.pinching = false;
27555 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27556 this.dragable = false;
27560 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27561 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27565 onMouseMove : function(e)
27569 if(!this.canvasLoaded){
27573 if (!this.dragable){
27577 var minX = Math.ceil(this.thumbEl.getLeft(true));
27578 var minY = Math.ceil(this.thumbEl.getTop(true));
27580 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27581 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27583 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27584 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27586 x = x - this.mouseX;
27587 y = y - this.mouseY;
27589 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27590 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27592 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27593 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27595 this.previewEl.setLeft(bgX);
27596 this.previewEl.setTop(bgY);
27598 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27599 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27602 onMouseUp : function(e)
27606 this.dragable = false;
27609 onMouseWheel : function(e)
27613 this.startScale = this.scale;
27615 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27617 if(!this.zoomable()){
27618 this.scale = this.startScale;
27627 zoomable : function()
27629 var minScale = this.thumbEl.getWidth() / this.minWidth;
27631 if(this.minWidth < this.minHeight){
27632 minScale = this.thumbEl.getHeight() / this.minHeight;
27635 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27636 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27640 (this.rotate == 0 || this.rotate == 180) &&
27642 width > this.imageEl.OriginWidth ||
27643 height > this.imageEl.OriginHeight ||
27644 (width < this.minWidth && height < this.minHeight)
27652 (this.rotate == 90 || this.rotate == 270) &&
27654 width > this.imageEl.OriginWidth ||
27655 height > this.imageEl.OriginHeight ||
27656 (width < this.minHeight && height < this.minWidth)
27663 !this.isDocument &&
27664 (this.rotate == 0 || this.rotate == 180) &&
27666 width < this.minWidth ||
27667 width > this.imageEl.OriginWidth ||
27668 height < this.minHeight ||
27669 height > this.imageEl.OriginHeight
27676 !this.isDocument &&
27677 (this.rotate == 90 || this.rotate == 270) &&
27679 width < this.minHeight ||
27680 width > this.imageEl.OriginWidth ||
27681 height < this.minWidth ||
27682 height > this.imageEl.OriginHeight
27692 onRotateLeft : function(e)
27694 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27696 var minScale = this.thumbEl.getWidth() / this.minWidth;
27698 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27699 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27701 this.startScale = this.scale;
27703 while (this.getScaleLevel() < minScale){
27705 this.scale = this.scale + 1;
27707 if(!this.zoomable()){
27712 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27713 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27718 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27725 this.scale = this.startScale;
27727 this.onRotateFail();
27732 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27734 if(this.isDocument){
27735 this.setThumbBoxSize();
27736 this.setThumbBoxPosition();
27737 this.setCanvasPosition();
27742 this.fireEvent('rotate', this, 'left');
27746 onRotateRight : function(e)
27748 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27750 var minScale = this.thumbEl.getWidth() / this.minWidth;
27752 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27753 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27755 this.startScale = this.scale;
27757 while (this.getScaleLevel() < minScale){
27759 this.scale = this.scale + 1;
27761 if(!this.zoomable()){
27766 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27767 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27772 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27779 this.scale = this.startScale;
27781 this.onRotateFail();
27786 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27788 if(this.isDocument){
27789 this.setThumbBoxSize();
27790 this.setThumbBoxPosition();
27791 this.setCanvasPosition();
27796 this.fireEvent('rotate', this, 'right');
27799 onRotateFail : function()
27801 this.errorEl.show(true);
27805 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27810 this.previewEl.dom.innerHTML = '';
27812 var canvasEl = document.createElement("canvas");
27814 var contextEl = canvasEl.getContext("2d");
27816 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27817 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27818 var center = this.imageEl.OriginWidth / 2;
27820 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27821 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27822 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27823 center = this.imageEl.OriginHeight / 2;
27826 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27828 contextEl.translate(center, center);
27829 contextEl.rotate(this.rotate * Math.PI / 180);
27831 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27833 this.canvasEl = document.createElement("canvas");
27835 this.contextEl = this.canvasEl.getContext("2d");
27837 switch (this.rotate) {
27840 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27841 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27843 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27848 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27849 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27851 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27852 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);
27856 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27861 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27862 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27864 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27865 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);
27869 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);
27874 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27875 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27877 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27878 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27882 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);
27889 this.previewEl.appendChild(this.canvasEl);
27891 this.setCanvasPosition();
27896 if(!this.canvasLoaded){
27900 var imageCanvas = document.createElement("canvas");
27902 var imageContext = imageCanvas.getContext("2d");
27904 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27905 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27907 var center = imageCanvas.width / 2;
27909 imageContext.translate(center, center);
27911 imageContext.rotate(this.rotate * Math.PI / 180);
27913 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27915 var canvas = document.createElement("canvas");
27917 var context = canvas.getContext("2d");
27919 canvas.width = this.minWidth;
27920 canvas.height = this.minHeight;
27922 switch (this.rotate) {
27925 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27926 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27928 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27929 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27931 var targetWidth = this.minWidth - 2 * x;
27932 var targetHeight = this.minHeight - 2 * y;
27936 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27937 scale = targetWidth / width;
27940 if(x > 0 && y == 0){
27941 scale = targetHeight / height;
27944 if(x > 0 && y > 0){
27945 scale = targetWidth / width;
27947 if(width < height){
27948 scale = targetHeight / height;
27952 context.scale(scale, scale);
27954 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27955 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27957 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27958 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27960 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27965 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27966 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27968 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27969 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27971 var targetWidth = this.minWidth - 2 * x;
27972 var targetHeight = this.minHeight - 2 * y;
27976 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27977 scale = targetWidth / width;
27980 if(x > 0 && y == 0){
27981 scale = targetHeight / height;
27984 if(x > 0 && y > 0){
27985 scale = targetWidth / width;
27987 if(width < height){
27988 scale = targetHeight / height;
27992 context.scale(scale, scale);
27994 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27995 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27997 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27998 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28000 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28002 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28007 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28008 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28010 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28011 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28013 var targetWidth = this.minWidth - 2 * x;
28014 var targetHeight = this.minHeight - 2 * y;
28018 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28019 scale = targetWidth / width;
28022 if(x > 0 && y == 0){
28023 scale = targetHeight / height;
28026 if(x > 0 && y > 0){
28027 scale = targetWidth / width;
28029 if(width < height){
28030 scale = targetHeight / height;
28034 context.scale(scale, scale);
28036 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28037 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28039 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28040 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28042 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28043 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28045 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28050 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28051 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28053 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28054 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28056 var targetWidth = this.minWidth - 2 * x;
28057 var targetHeight = this.minHeight - 2 * y;
28061 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28062 scale = targetWidth / width;
28065 if(x > 0 && y == 0){
28066 scale = targetHeight / height;
28069 if(x > 0 && y > 0){
28070 scale = targetWidth / width;
28072 if(width < height){
28073 scale = targetHeight / height;
28077 context.scale(scale, scale);
28079 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28080 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28082 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28083 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28085 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28087 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28094 this.cropData = canvas.toDataURL(this.cropType);
28096 if(this.fireEvent('crop', this, this.cropData) !== false){
28097 this.process(this.file, this.cropData);
28104 setThumbBoxSize : function()
28108 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28109 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28110 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28112 this.minWidth = width;
28113 this.minHeight = height;
28115 if(this.rotate == 90 || this.rotate == 270){
28116 this.minWidth = height;
28117 this.minHeight = width;
28122 width = Math.ceil(this.minWidth * height / this.minHeight);
28124 if(this.minWidth > this.minHeight){
28126 height = Math.ceil(this.minHeight * width / this.minWidth);
28129 this.thumbEl.setStyle({
28130 width : width + 'px',
28131 height : height + 'px'
28138 setThumbBoxPosition : function()
28140 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28141 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28143 this.thumbEl.setLeft(x);
28144 this.thumbEl.setTop(y);
28148 baseRotateLevel : function()
28150 this.baseRotate = 1;
28153 typeof(this.exif) != 'undefined' &&
28154 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28155 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28157 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28160 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28164 baseScaleLevel : function()
28168 if(this.isDocument){
28170 if(this.baseRotate == 6 || this.baseRotate == 8){
28172 height = this.thumbEl.getHeight();
28173 this.baseScale = height / this.imageEl.OriginWidth;
28175 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28176 width = this.thumbEl.getWidth();
28177 this.baseScale = width / this.imageEl.OriginHeight;
28183 height = this.thumbEl.getHeight();
28184 this.baseScale = height / this.imageEl.OriginHeight;
28186 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28187 width = this.thumbEl.getWidth();
28188 this.baseScale = width / this.imageEl.OriginWidth;
28194 if(this.baseRotate == 6 || this.baseRotate == 8){
28196 width = this.thumbEl.getHeight();
28197 this.baseScale = width / this.imageEl.OriginHeight;
28199 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28200 height = this.thumbEl.getWidth();
28201 this.baseScale = height / this.imageEl.OriginHeight;
28204 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28205 height = this.thumbEl.getWidth();
28206 this.baseScale = height / this.imageEl.OriginHeight;
28208 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28209 width = this.thumbEl.getHeight();
28210 this.baseScale = width / this.imageEl.OriginWidth;
28217 width = this.thumbEl.getWidth();
28218 this.baseScale = width / this.imageEl.OriginWidth;
28220 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28221 height = this.thumbEl.getHeight();
28222 this.baseScale = height / this.imageEl.OriginHeight;
28225 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28227 height = this.thumbEl.getHeight();
28228 this.baseScale = height / this.imageEl.OriginHeight;
28230 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28231 width = this.thumbEl.getWidth();
28232 this.baseScale = width / this.imageEl.OriginWidth;
28240 getScaleLevel : function()
28242 return this.baseScale * Math.pow(1.1, this.scale);
28245 onTouchStart : function(e)
28247 if(!this.canvasLoaded){
28248 this.beforeSelectFile(e);
28252 var touches = e.browserEvent.touches;
28258 if(touches.length == 1){
28259 this.onMouseDown(e);
28263 if(touches.length != 2){
28269 for(var i = 0, finger; finger = touches[i]; i++){
28270 coords.push(finger.pageX, finger.pageY);
28273 var x = Math.pow(coords[0] - coords[2], 2);
28274 var y = Math.pow(coords[1] - coords[3], 2);
28276 this.startDistance = Math.sqrt(x + y);
28278 this.startScale = this.scale;
28280 this.pinching = true;
28281 this.dragable = false;
28285 onTouchMove : function(e)
28287 if(!this.pinching && !this.dragable){
28291 var touches = e.browserEvent.touches;
28298 this.onMouseMove(e);
28304 for(var i = 0, finger; finger = touches[i]; i++){
28305 coords.push(finger.pageX, finger.pageY);
28308 var x = Math.pow(coords[0] - coords[2], 2);
28309 var y = Math.pow(coords[1] - coords[3], 2);
28311 this.endDistance = Math.sqrt(x + y);
28313 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28315 if(!this.zoomable()){
28316 this.scale = this.startScale;
28324 onTouchEnd : function(e)
28326 this.pinching = false;
28327 this.dragable = false;
28331 process : function(file, crop)
28334 this.maskEl.mask(this.loadingText);
28337 this.xhr = new XMLHttpRequest();
28339 file.xhr = this.xhr;
28341 this.xhr.open(this.method, this.url, true);
28344 "Accept": "application/json",
28345 "Cache-Control": "no-cache",
28346 "X-Requested-With": "XMLHttpRequest"
28349 for (var headerName in headers) {
28350 var headerValue = headers[headerName];
28352 this.xhr.setRequestHeader(headerName, headerValue);
28358 this.xhr.onload = function()
28360 _this.xhrOnLoad(_this.xhr);
28363 this.xhr.onerror = function()
28365 _this.xhrOnError(_this.xhr);
28368 var formData = new FormData();
28370 formData.append('returnHTML', 'NO');
28373 formData.append('crop', crop);
28376 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28377 formData.append(this.paramName, file, file.name);
28380 if(typeof(file.filename) != 'undefined'){
28381 formData.append('filename', file.filename);
28384 if(typeof(file.mimetype) != 'undefined'){
28385 formData.append('mimetype', file.mimetype);
28388 if(this.fireEvent('arrange', this, formData) != false){
28389 this.xhr.send(formData);
28393 xhrOnLoad : function(xhr)
28396 this.maskEl.unmask();
28399 if (xhr.readyState !== 4) {
28400 this.fireEvent('exception', this, xhr);
28404 var response = Roo.decode(xhr.responseText);
28406 if(!response.success){
28407 this.fireEvent('exception', this, xhr);
28411 var response = Roo.decode(xhr.responseText);
28413 this.fireEvent('upload', this, response);
28417 xhrOnError : function()
28420 this.maskEl.unmask();
28423 Roo.log('xhr on error');
28425 var response = Roo.decode(xhr.responseText);
28431 prepare : function(file)
28434 this.maskEl.mask(this.loadingText);
28440 if(typeof(file) === 'string'){
28441 this.loadCanvas(file);
28445 if(!file || !this.urlAPI){
28450 this.cropType = file.type;
28454 if(this.fireEvent('prepare', this, this.file) != false){
28456 var reader = new FileReader();
28458 reader.onload = function (e) {
28459 if (e.target.error) {
28460 Roo.log(e.target.error);
28464 var buffer = e.target.result,
28465 dataView = new DataView(buffer),
28467 maxOffset = dataView.byteLength - 4,
28471 if (dataView.getUint16(0) === 0xffd8) {
28472 while (offset < maxOffset) {
28473 markerBytes = dataView.getUint16(offset);
28475 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28476 markerLength = dataView.getUint16(offset + 2) + 2;
28477 if (offset + markerLength > dataView.byteLength) {
28478 Roo.log('Invalid meta data: Invalid segment size.');
28482 if(markerBytes == 0xffe1){
28483 _this.parseExifData(
28490 offset += markerLength;
28500 var url = _this.urlAPI.createObjectURL(_this.file);
28502 _this.loadCanvas(url);
28507 reader.readAsArrayBuffer(this.file);
28513 parseExifData : function(dataView, offset, length)
28515 var tiffOffset = offset + 10,
28519 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28520 // No Exif data, might be XMP data instead
28524 // Check for the ASCII code for "Exif" (0x45786966):
28525 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28526 // No Exif data, might be XMP data instead
28529 if (tiffOffset + 8 > dataView.byteLength) {
28530 Roo.log('Invalid Exif data: Invalid segment size.');
28533 // Check for the two null bytes:
28534 if (dataView.getUint16(offset + 8) !== 0x0000) {
28535 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28538 // Check the byte alignment:
28539 switch (dataView.getUint16(tiffOffset)) {
28541 littleEndian = true;
28544 littleEndian = false;
28547 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28550 // Check for the TIFF tag marker (0x002A):
28551 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28552 Roo.log('Invalid Exif data: Missing TIFF marker.');
28555 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28556 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28558 this.parseExifTags(
28561 tiffOffset + dirOffset,
28566 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28571 if (dirOffset + 6 > dataView.byteLength) {
28572 Roo.log('Invalid Exif data: Invalid directory offset.');
28575 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28576 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28577 if (dirEndOffset + 4 > dataView.byteLength) {
28578 Roo.log('Invalid Exif data: Invalid directory size.');
28581 for (i = 0; i < tagsNumber; i += 1) {
28585 dirOffset + 2 + 12 * i, // tag offset
28589 // Return the offset to the next directory:
28590 return dataView.getUint32(dirEndOffset, littleEndian);
28593 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28595 var tag = dataView.getUint16(offset, littleEndian);
28597 this.exif[tag] = this.getExifValue(
28601 dataView.getUint16(offset + 2, littleEndian), // tag type
28602 dataView.getUint32(offset + 4, littleEndian), // tag length
28607 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28609 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28618 Roo.log('Invalid Exif data: Invalid tag type.');
28622 tagSize = tagType.size * length;
28623 // Determine if the value is contained in the dataOffset bytes,
28624 // or if the value at the dataOffset is a pointer to the actual data:
28625 dataOffset = tagSize > 4 ?
28626 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28627 if (dataOffset + tagSize > dataView.byteLength) {
28628 Roo.log('Invalid Exif data: Invalid data offset.');
28631 if (length === 1) {
28632 return tagType.getValue(dataView, dataOffset, littleEndian);
28635 for (i = 0; i < length; i += 1) {
28636 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28639 if (tagType.ascii) {
28641 // Concatenate the chars:
28642 for (i = 0; i < values.length; i += 1) {
28644 // Ignore the terminating NULL byte(s):
28645 if (c === '\u0000') {
28657 Roo.apply(Roo.bootstrap.UploadCropbox, {
28659 'Orientation': 0x0112
28663 1: 0, //'top-left',
28665 3: 180, //'bottom-right',
28666 // 4: 'bottom-left',
28668 6: 90, //'right-top',
28669 // 7: 'right-bottom',
28670 8: 270 //'left-bottom'
28674 // byte, 8-bit unsigned int:
28676 getValue: function (dataView, dataOffset) {
28677 return dataView.getUint8(dataOffset);
28681 // ascii, 8-bit byte:
28683 getValue: function (dataView, dataOffset) {
28684 return String.fromCharCode(dataView.getUint8(dataOffset));
28689 // short, 16 bit int:
28691 getValue: function (dataView, dataOffset, littleEndian) {
28692 return dataView.getUint16(dataOffset, littleEndian);
28696 // long, 32 bit int:
28698 getValue: function (dataView, dataOffset, littleEndian) {
28699 return dataView.getUint32(dataOffset, littleEndian);
28703 // rational = two long values, first is numerator, second is denominator:
28705 getValue: function (dataView, dataOffset, littleEndian) {
28706 return dataView.getUint32(dataOffset, littleEndian) /
28707 dataView.getUint32(dataOffset + 4, littleEndian);
28711 // slong, 32 bit signed int:
28713 getValue: function (dataView, dataOffset, littleEndian) {
28714 return dataView.getInt32(dataOffset, littleEndian);
28718 // srational, two slongs, first is numerator, second is denominator:
28720 getValue: function (dataView, dataOffset, littleEndian) {
28721 return dataView.getInt32(dataOffset, littleEndian) /
28722 dataView.getInt32(dataOffset + 4, littleEndian);
28732 cls : 'btn-group roo-upload-cropbox-rotate-left',
28733 action : 'rotate-left',
28737 cls : 'btn btn-default',
28738 html : '<i class="fa fa-undo"></i>'
28744 cls : 'btn-group roo-upload-cropbox-picture',
28745 action : 'picture',
28749 cls : 'btn btn-default',
28750 html : '<i class="fa fa-picture-o"></i>'
28756 cls : 'btn-group roo-upload-cropbox-rotate-right',
28757 action : 'rotate-right',
28761 cls : 'btn btn-default',
28762 html : '<i class="fa fa-repeat"></i>'
28770 cls : 'btn-group roo-upload-cropbox-rotate-left',
28771 action : 'rotate-left',
28775 cls : 'btn btn-default',
28776 html : '<i class="fa fa-undo"></i>'
28782 cls : 'btn-group roo-upload-cropbox-download',
28783 action : 'download',
28787 cls : 'btn btn-default',
28788 html : '<i class="fa fa-download"></i>'
28794 cls : 'btn-group roo-upload-cropbox-crop',
28799 cls : 'btn btn-default',
28800 html : '<i class="fa fa-crop"></i>'
28806 cls : 'btn-group roo-upload-cropbox-trash',
28811 cls : 'btn btn-default',
28812 html : '<i class="fa fa-trash"></i>'
28818 cls : 'btn-group roo-upload-cropbox-rotate-right',
28819 action : 'rotate-right',
28823 cls : 'btn btn-default',
28824 html : '<i class="fa fa-repeat"></i>'
28832 cls : 'btn-group roo-upload-cropbox-rotate-left',
28833 action : 'rotate-left',
28837 cls : 'btn btn-default',
28838 html : '<i class="fa fa-undo"></i>'
28844 cls : 'btn-group roo-upload-cropbox-rotate-right',
28845 action : 'rotate-right',
28849 cls : 'btn btn-default',
28850 html : '<i class="fa fa-repeat"></i>'
28863 * @class Roo.bootstrap.DocumentManager
28864 * @extends Roo.bootstrap.Component
28865 * Bootstrap DocumentManager class
28866 * @cfg {String} paramName default 'imageUpload'
28867 * @cfg {String} toolTipName default 'filename'
28868 * @cfg {String} method default POST
28869 * @cfg {String} url action url
28870 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28871 * @cfg {Boolean} multiple multiple upload default true
28872 * @cfg {Number} thumbSize default 300
28873 * @cfg {String} fieldLabel
28874 * @cfg {Number} labelWidth default 4
28875 * @cfg {String} labelAlign (left|top) default left
28876 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28877 * @cfg {Number} labellg set the width of label (1-12)
28878 * @cfg {Number} labelmd set the width of label (1-12)
28879 * @cfg {Number} labelsm set the width of label (1-12)
28880 * @cfg {Number} labelxs set the width of label (1-12)
28883 * Create a new DocumentManager
28884 * @param {Object} config The config object
28887 Roo.bootstrap.DocumentManager = function(config){
28888 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28891 this.delegates = [];
28896 * Fire when initial the DocumentManager
28897 * @param {Roo.bootstrap.DocumentManager} this
28902 * inspect selected file
28903 * @param {Roo.bootstrap.DocumentManager} this
28904 * @param {File} file
28909 * Fire when xhr load exception
28910 * @param {Roo.bootstrap.DocumentManager} this
28911 * @param {XMLHttpRequest} xhr
28913 "exception" : true,
28915 * @event afterupload
28916 * Fire when xhr load exception
28917 * @param {Roo.bootstrap.DocumentManager} this
28918 * @param {XMLHttpRequest} xhr
28920 "afterupload" : true,
28923 * prepare the form data
28924 * @param {Roo.bootstrap.DocumentManager} this
28925 * @param {Object} formData
28930 * Fire when remove the file
28931 * @param {Roo.bootstrap.DocumentManager} this
28932 * @param {Object} file
28937 * Fire after refresh the file
28938 * @param {Roo.bootstrap.DocumentManager} this
28943 * Fire after click the image
28944 * @param {Roo.bootstrap.DocumentManager} this
28945 * @param {Object} file
28950 * Fire when upload a image and editable set to true
28951 * @param {Roo.bootstrap.DocumentManager} this
28952 * @param {Object} file
28956 * @event beforeselectfile
28957 * Fire before select file
28958 * @param {Roo.bootstrap.DocumentManager} this
28960 "beforeselectfile" : true,
28963 * Fire before process file
28964 * @param {Roo.bootstrap.DocumentManager} this
28965 * @param {Object} file
28969 * @event previewrendered
28970 * Fire when preview rendered
28971 * @param {Roo.bootstrap.DocumentManager} this
28972 * @param {Object} file
28974 "previewrendered" : true,
28977 "previewResize" : true
28982 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28991 paramName : 'imageUpload',
28992 toolTipName : 'filename',
28995 labelAlign : 'left',
29005 getAutoCreate : function()
29007 var managerWidget = {
29009 cls : 'roo-document-manager',
29013 cls : 'roo-document-manager-selector',
29018 cls : 'roo-document-manager-uploader',
29022 cls : 'roo-document-manager-upload-btn',
29023 html : '<i class="fa fa-plus"></i>'
29034 cls : 'column col-md-12',
29039 if(this.fieldLabel.length){
29044 cls : 'column col-md-12',
29045 html : this.fieldLabel
29049 cls : 'column col-md-12',
29054 if(this.labelAlign == 'left'){
29059 html : this.fieldLabel
29068 if(this.labelWidth > 12){
29069 content[0].style = "width: " + this.labelWidth + 'px';
29072 if(this.labelWidth < 13 && this.labelmd == 0){
29073 this.labelmd = this.labelWidth;
29076 if(this.labellg > 0){
29077 content[0].cls += ' col-lg-' + this.labellg;
29078 content[1].cls += ' col-lg-' + (12 - this.labellg);
29081 if(this.labelmd > 0){
29082 content[0].cls += ' col-md-' + this.labelmd;
29083 content[1].cls += ' col-md-' + (12 - this.labelmd);
29086 if(this.labelsm > 0){
29087 content[0].cls += ' col-sm-' + this.labelsm;
29088 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29091 if(this.labelxs > 0){
29092 content[0].cls += ' col-xs-' + this.labelxs;
29093 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29101 cls : 'row clearfix',
29109 initEvents : function()
29111 this.managerEl = this.el.select('.roo-document-manager', true).first();
29112 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29114 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29115 this.selectorEl.hide();
29118 this.selectorEl.attr('multiple', 'multiple');
29121 this.selectorEl.on('change', this.onFileSelected, this);
29123 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29124 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29126 this.uploader.on('click', this.onUploaderClick, this);
29128 this.renderProgressDialog();
29132 window.addEventListener("resize", function() { _this.refresh(); } );
29134 this.fireEvent('initial', this);
29137 renderProgressDialog : function()
29141 this.progressDialog = new Roo.bootstrap.Modal({
29142 cls : 'roo-document-manager-progress-dialog',
29143 allow_close : false,
29153 btnclick : function() {
29154 _this.uploadCancel();
29160 this.progressDialog.render(Roo.get(document.body));
29162 this.progress = new Roo.bootstrap.Progress({
29163 cls : 'roo-document-manager-progress',
29168 this.progress.render(this.progressDialog.getChildContainer());
29170 this.progressBar = new Roo.bootstrap.ProgressBar({
29171 cls : 'roo-document-manager-progress-bar',
29174 aria_valuemax : 12,
29178 this.progressBar.render(this.progress.getChildContainer());
29181 onUploaderClick : function(e)
29183 e.preventDefault();
29185 if(this.fireEvent('beforeselectfile', this) != false){
29186 this.selectorEl.dom.click();
29191 onFileSelected : function(e)
29193 e.preventDefault();
29195 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29199 Roo.each(this.selectorEl.dom.files, function(file){
29200 if(this.fireEvent('inspect', this, file) != false){
29201 this.files.push(file);
29211 this.selectorEl.dom.value = '';
29213 if(!this.files || !this.files.length){
29217 if(this.boxes > 0 && this.files.length > this.boxes){
29218 this.files = this.files.slice(0, this.boxes);
29221 this.uploader.show();
29223 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29224 this.uploader.hide();
29233 Roo.each(this.files, function(file){
29235 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29236 var f = this.renderPreview(file);
29241 if(file.type.indexOf('image') != -1){
29242 this.delegates.push(
29244 _this.process(file);
29245 }).createDelegate(this)
29253 _this.process(file);
29254 }).createDelegate(this)
29259 this.files = files;
29261 this.delegates = this.delegates.concat(docs);
29263 if(!this.delegates.length){
29268 this.progressBar.aria_valuemax = this.delegates.length;
29275 arrange : function()
29277 if(!this.delegates.length){
29278 this.progressDialog.hide();
29283 var delegate = this.delegates.shift();
29285 this.progressDialog.show();
29287 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29289 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29294 refresh : function()
29296 this.uploader.show();
29298 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29299 this.uploader.hide();
29302 Roo.isTouch ? this.closable(false) : this.closable(true);
29304 this.fireEvent('refresh', this);
29307 onRemove : function(e, el, o)
29309 e.preventDefault();
29311 this.fireEvent('remove', this, o);
29315 remove : function(o)
29319 Roo.each(this.files, function(file){
29320 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29329 this.files = files;
29336 Roo.each(this.files, function(file){
29341 file.target.remove();
29350 onClick : function(e, el, o)
29352 e.preventDefault();
29354 this.fireEvent('click', this, o);
29358 closable : function(closable)
29360 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29362 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29374 xhrOnLoad : function(xhr)
29376 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29380 if (xhr.readyState !== 4) {
29382 this.fireEvent('exception', this, xhr);
29386 var response = Roo.decode(xhr.responseText);
29388 if(!response.success){
29390 this.fireEvent('exception', this, xhr);
29394 var file = this.renderPreview(response.data);
29396 this.files.push(file);
29400 this.fireEvent('afterupload', this, xhr);
29404 xhrOnError : function(xhr)
29406 Roo.log('xhr on error');
29408 var response = Roo.decode(xhr.responseText);
29415 process : function(file)
29417 if(this.fireEvent('process', this, file) !== false){
29418 if(this.editable && file.type.indexOf('image') != -1){
29419 this.fireEvent('edit', this, file);
29423 this.uploadStart(file, false);
29430 uploadStart : function(file, crop)
29432 this.xhr = new XMLHttpRequest();
29434 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29439 file.xhr = this.xhr;
29441 this.managerEl.createChild({
29443 cls : 'roo-document-manager-loading',
29447 tooltip : file.name,
29448 cls : 'roo-document-manager-thumb',
29449 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29455 this.xhr.open(this.method, this.url, true);
29458 "Accept": "application/json",
29459 "Cache-Control": "no-cache",
29460 "X-Requested-With": "XMLHttpRequest"
29463 for (var headerName in headers) {
29464 var headerValue = headers[headerName];
29466 this.xhr.setRequestHeader(headerName, headerValue);
29472 this.xhr.onload = function()
29474 _this.xhrOnLoad(_this.xhr);
29477 this.xhr.onerror = function()
29479 _this.xhrOnError(_this.xhr);
29482 var formData = new FormData();
29484 formData.append('returnHTML', 'NO');
29487 formData.append('crop', crop);
29490 formData.append(this.paramName, file, file.name);
29497 if(this.fireEvent('prepare', this, formData, options) != false){
29499 if(options.manually){
29503 this.xhr.send(formData);
29507 this.uploadCancel();
29510 uploadCancel : function()
29516 this.delegates = [];
29518 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29525 renderPreview : function(file)
29527 if(typeof(file.target) != 'undefined' && file.target){
29531 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29533 var previewEl = this.managerEl.createChild({
29535 cls : 'roo-document-manager-preview',
29539 tooltip : file[this.toolTipName],
29540 cls : 'roo-document-manager-thumb',
29541 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29546 html : '<i class="fa fa-times-circle"></i>'
29551 var close = previewEl.select('button.close', true).first();
29553 close.on('click', this.onRemove, this, file);
29555 file.target = previewEl;
29557 var image = previewEl.select('img', true).first();
29561 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29563 image.on('click', this.onClick, this, file);
29565 this.fireEvent('previewrendered', this, file);
29571 onPreviewLoad : function(file, image)
29573 if(typeof(file.target) == 'undefined' || !file.target){
29577 var width = image.dom.naturalWidth || image.dom.width;
29578 var height = image.dom.naturalHeight || image.dom.height;
29580 if(!this.previewResize) {
29584 if(width > height){
29585 file.target.addClass('wide');
29589 file.target.addClass('tall');
29594 uploadFromSource : function(file, crop)
29596 this.xhr = new XMLHttpRequest();
29598 this.managerEl.createChild({
29600 cls : 'roo-document-manager-loading',
29604 tooltip : file.name,
29605 cls : 'roo-document-manager-thumb',
29606 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29612 this.xhr.open(this.method, this.url, true);
29615 "Accept": "application/json",
29616 "Cache-Control": "no-cache",
29617 "X-Requested-With": "XMLHttpRequest"
29620 for (var headerName in headers) {
29621 var headerValue = headers[headerName];
29623 this.xhr.setRequestHeader(headerName, headerValue);
29629 this.xhr.onload = function()
29631 _this.xhrOnLoad(_this.xhr);
29634 this.xhr.onerror = function()
29636 _this.xhrOnError(_this.xhr);
29639 var formData = new FormData();
29641 formData.append('returnHTML', 'NO');
29643 formData.append('crop', crop);
29645 if(typeof(file.filename) != 'undefined'){
29646 formData.append('filename', file.filename);
29649 if(typeof(file.mimetype) != 'undefined'){
29650 formData.append('mimetype', file.mimetype);
29655 if(this.fireEvent('prepare', this, formData) != false){
29656 this.xhr.send(formData);
29666 * @class Roo.bootstrap.DocumentViewer
29667 * @extends Roo.bootstrap.Component
29668 * Bootstrap DocumentViewer class
29669 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29670 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29673 * Create a new DocumentViewer
29674 * @param {Object} config The config object
29677 Roo.bootstrap.DocumentViewer = function(config){
29678 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29683 * Fire after initEvent
29684 * @param {Roo.bootstrap.DocumentViewer} this
29690 * @param {Roo.bootstrap.DocumentViewer} this
29695 * Fire after download button
29696 * @param {Roo.bootstrap.DocumentViewer} this
29701 * Fire after trash button
29702 * @param {Roo.bootstrap.DocumentViewer} this
29709 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29711 showDownload : true,
29715 getAutoCreate : function()
29719 cls : 'roo-document-viewer',
29723 cls : 'roo-document-viewer-body',
29727 cls : 'roo-document-viewer-thumb',
29731 cls : 'roo-document-viewer-image'
29739 cls : 'roo-document-viewer-footer',
29742 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29746 cls : 'btn-group roo-document-viewer-download',
29750 cls : 'btn btn-default',
29751 html : '<i class="fa fa-download"></i>'
29757 cls : 'btn-group roo-document-viewer-trash',
29761 cls : 'btn btn-default',
29762 html : '<i class="fa fa-trash"></i>'
29775 initEvents : function()
29777 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29778 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29780 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29781 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29783 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29784 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29786 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29787 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29789 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29790 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29792 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29793 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29795 this.bodyEl.on('click', this.onClick, this);
29796 this.downloadBtn.on('click', this.onDownload, this);
29797 this.trashBtn.on('click', this.onTrash, this);
29799 this.downloadBtn.hide();
29800 this.trashBtn.hide();
29802 if(this.showDownload){
29803 this.downloadBtn.show();
29806 if(this.showTrash){
29807 this.trashBtn.show();
29810 if(!this.showDownload && !this.showTrash) {
29811 this.footerEl.hide();
29816 initial : function()
29818 this.fireEvent('initial', this);
29822 onClick : function(e)
29824 e.preventDefault();
29826 this.fireEvent('click', this);
29829 onDownload : function(e)
29831 e.preventDefault();
29833 this.fireEvent('download', this);
29836 onTrash : function(e)
29838 e.preventDefault();
29840 this.fireEvent('trash', this);
29852 * @class Roo.bootstrap.NavProgressBar
29853 * @extends Roo.bootstrap.Component
29854 * Bootstrap NavProgressBar class
29857 * Create a new nav progress bar
29858 * @param {Object} config The config object
29861 Roo.bootstrap.NavProgressBar = function(config){
29862 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29864 this.bullets = this.bullets || [];
29866 // Roo.bootstrap.NavProgressBar.register(this);
29870 * Fires when the active item changes
29871 * @param {Roo.bootstrap.NavProgressBar} this
29872 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29873 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29880 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29885 getAutoCreate : function()
29887 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29891 cls : 'roo-navigation-bar-group',
29895 cls : 'roo-navigation-top-bar'
29899 cls : 'roo-navigation-bullets-bar',
29903 cls : 'roo-navigation-bar'
29910 cls : 'roo-navigation-bottom-bar'
29920 initEvents: function()
29925 onRender : function(ct, position)
29927 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29929 if(this.bullets.length){
29930 Roo.each(this.bullets, function(b){
29939 addItem : function(cfg)
29941 var item = new Roo.bootstrap.NavProgressItem(cfg);
29943 item.parentId = this.id;
29944 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29947 var top = new Roo.bootstrap.Element({
29949 cls : 'roo-navigation-bar-text'
29952 var bottom = new Roo.bootstrap.Element({
29954 cls : 'roo-navigation-bar-text'
29957 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29958 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29960 var topText = new Roo.bootstrap.Element({
29962 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29965 var bottomText = new Roo.bootstrap.Element({
29967 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29970 topText.onRender(top.el, null);
29971 bottomText.onRender(bottom.el, null);
29974 item.bottomEl = bottom;
29977 this.barItems.push(item);
29982 getActive : function()
29984 var active = false;
29986 Roo.each(this.barItems, function(v){
29988 if (!v.isActive()) {
30000 setActiveItem : function(item)
30004 Roo.each(this.barItems, function(v){
30005 if (v.rid == item.rid) {
30009 if (v.isActive()) {
30010 v.setActive(false);
30015 item.setActive(true);
30017 this.fireEvent('changed', this, item, prev);
30020 getBarItem: function(rid)
30024 Roo.each(this.barItems, function(e) {
30025 if (e.rid != rid) {
30036 indexOfItem : function(item)
30040 Roo.each(this.barItems, function(v, i){
30042 if (v.rid != item.rid) {
30053 setActiveNext : function()
30055 var i = this.indexOfItem(this.getActive());
30057 if (i > this.barItems.length) {
30061 this.setActiveItem(this.barItems[i+1]);
30064 setActivePrev : function()
30066 var i = this.indexOfItem(this.getActive());
30072 this.setActiveItem(this.barItems[i-1]);
30075 format : function()
30077 if(!this.barItems.length){
30081 var width = 100 / this.barItems.length;
30083 Roo.each(this.barItems, function(i){
30084 i.el.setStyle('width', width + '%');
30085 i.topEl.el.setStyle('width', width + '%');
30086 i.bottomEl.el.setStyle('width', width + '%');
30095 * Nav Progress Item
30100 * @class Roo.bootstrap.NavProgressItem
30101 * @extends Roo.bootstrap.Component
30102 * Bootstrap NavProgressItem class
30103 * @cfg {String} rid the reference id
30104 * @cfg {Boolean} active (true|false) Is item active default false
30105 * @cfg {Boolean} disabled (true|false) Is item active default false
30106 * @cfg {String} html
30107 * @cfg {String} position (top|bottom) text position default bottom
30108 * @cfg {String} icon show icon instead of number
30111 * Create a new NavProgressItem
30112 * @param {Object} config The config object
30114 Roo.bootstrap.NavProgressItem = function(config){
30115 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30120 * The raw click event for the entire grid.
30121 * @param {Roo.bootstrap.NavProgressItem} this
30122 * @param {Roo.EventObject} e
30129 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30135 position : 'bottom',
30138 getAutoCreate : function()
30140 var iconCls = 'roo-navigation-bar-item-icon';
30142 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30146 cls: 'roo-navigation-bar-item',
30156 cfg.cls += ' active';
30159 cfg.cls += ' disabled';
30165 disable : function()
30167 this.setDisabled(true);
30170 enable : function()
30172 this.setDisabled(false);
30175 initEvents: function()
30177 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30179 this.iconEl.on('click', this.onClick, this);
30182 onClick : function(e)
30184 e.preventDefault();
30190 if(this.fireEvent('click', this, e) === false){
30194 this.parent().setActiveItem(this);
30197 isActive: function ()
30199 return this.active;
30202 setActive : function(state)
30204 if(this.active == state){
30208 this.active = state;
30211 this.el.addClass('active');
30215 this.el.removeClass('active');
30220 setDisabled : function(state)
30222 if(this.disabled == state){
30226 this.disabled = state;
30229 this.el.addClass('disabled');
30233 this.el.removeClass('disabled');
30236 tooltipEl : function()
30238 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30251 * @class Roo.bootstrap.FieldLabel
30252 * @extends Roo.bootstrap.Component
30253 * Bootstrap FieldLabel class
30254 * @cfg {String} html contents of the element
30255 * @cfg {String} tag tag of the element default label
30256 * @cfg {String} cls class of the element
30257 * @cfg {String} target label target
30258 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30259 * @cfg {String} invalidClass default "text-warning"
30260 * @cfg {String} validClass default "text-success"
30261 * @cfg {String} iconTooltip default "This field is required"
30262 * @cfg {String} indicatorpos (left|right) default left
30265 * Create a new FieldLabel
30266 * @param {Object} config The config object
30269 Roo.bootstrap.FieldLabel = function(config){
30270 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30275 * Fires after the field has been marked as invalid.
30276 * @param {Roo.form.FieldLabel} this
30277 * @param {String} msg The validation message
30282 * Fires after the field has been validated with no errors.
30283 * @param {Roo.form.FieldLabel} this
30289 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30296 invalidClass : 'has-warning',
30297 validClass : 'has-success',
30298 iconTooltip : 'This field is required',
30299 indicatorpos : 'left',
30301 getAutoCreate : function(){
30304 if (!this.allowBlank) {
30310 cls : 'roo-bootstrap-field-label ' + this.cls,
30315 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30316 tooltip : this.iconTooltip
30325 if(this.indicatorpos == 'right'){
30328 cls : 'roo-bootstrap-field-label ' + this.cls,
30337 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30338 tooltip : this.iconTooltip
30347 initEvents: function()
30349 Roo.bootstrap.Element.superclass.initEvents.call(this);
30351 this.indicator = this.indicatorEl();
30353 if(this.indicator){
30354 this.indicator.removeClass('visible');
30355 this.indicator.addClass('invisible');
30358 Roo.bootstrap.FieldLabel.register(this);
30361 indicatorEl : function()
30363 var indicator = this.el.select('i.roo-required-indicator',true).first();
30374 * Mark this field as valid
30376 markValid : function()
30378 if(this.indicator){
30379 this.indicator.removeClass('visible');
30380 this.indicator.addClass('invisible');
30383 this.el.removeClass(this.invalidClass);
30385 this.el.addClass(this.validClass);
30387 this.fireEvent('valid', this);
30391 * Mark this field as invalid
30392 * @param {String} msg The validation message
30394 markInvalid : function(msg)
30396 if(this.indicator){
30397 this.indicator.removeClass('invisible');
30398 this.indicator.addClass('visible');
30401 this.el.removeClass(this.validClass);
30403 this.el.addClass(this.invalidClass);
30405 this.fireEvent('invalid', this, msg);
30411 Roo.apply(Roo.bootstrap.FieldLabel, {
30416 * register a FieldLabel Group
30417 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30419 register : function(label)
30421 if(this.groups.hasOwnProperty(label.target)){
30425 this.groups[label.target] = label;
30429 * fetch a FieldLabel Group based on the target
30430 * @param {string} target
30431 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30433 get: function(target) {
30434 if (typeof(this.groups[target]) == 'undefined') {
30438 return this.groups[target] ;
30447 * page DateSplitField.
30453 * @class Roo.bootstrap.DateSplitField
30454 * @extends Roo.bootstrap.Component
30455 * Bootstrap DateSplitField class
30456 * @cfg {string} fieldLabel - the label associated
30457 * @cfg {Number} labelWidth set the width of label (0-12)
30458 * @cfg {String} labelAlign (top|left)
30459 * @cfg {Boolean} dayAllowBlank (true|false) default false
30460 * @cfg {Boolean} monthAllowBlank (true|false) default false
30461 * @cfg {Boolean} yearAllowBlank (true|false) default false
30462 * @cfg {string} dayPlaceholder
30463 * @cfg {string} monthPlaceholder
30464 * @cfg {string} yearPlaceholder
30465 * @cfg {string} dayFormat default 'd'
30466 * @cfg {string} monthFormat default 'm'
30467 * @cfg {string} yearFormat default 'Y'
30468 * @cfg {Number} labellg set the width of label (1-12)
30469 * @cfg {Number} labelmd set the width of label (1-12)
30470 * @cfg {Number} labelsm set the width of label (1-12)
30471 * @cfg {Number} labelxs set the width of label (1-12)
30475 * Create a new DateSplitField
30476 * @param {Object} config The config object
30479 Roo.bootstrap.DateSplitField = function(config){
30480 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30486 * getting the data of years
30487 * @param {Roo.bootstrap.DateSplitField} this
30488 * @param {Object} years
30493 * getting the data of days
30494 * @param {Roo.bootstrap.DateSplitField} this
30495 * @param {Object} days
30500 * Fires after the field has been marked as invalid.
30501 * @param {Roo.form.Field} this
30502 * @param {String} msg The validation message
30507 * Fires after the field has been validated with no errors.
30508 * @param {Roo.form.Field} this
30514 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30517 labelAlign : 'top',
30519 dayAllowBlank : false,
30520 monthAllowBlank : false,
30521 yearAllowBlank : false,
30522 dayPlaceholder : '',
30523 monthPlaceholder : '',
30524 yearPlaceholder : '',
30528 isFormField : true,
30534 getAutoCreate : function()
30538 cls : 'row roo-date-split-field-group',
30543 cls : 'form-hidden-field roo-date-split-field-group-value',
30549 var labelCls = 'col-md-12';
30550 var contentCls = 'col-md-4';
30552 if(this.fieldLabel){
30556 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30560 html : this.fieldLabel
30565 if(this.labelAlign == 'left'){
30567 if(this.labelWidth > 12){
30568 label.style = "width: " + this.labelWidth + 'px';
30571 if(this.labelWidth < 13 && this.labelmd == 0){
30572 this.labelmd = this.labelWidth;
30575 if(this.labellg > 0){
30576 labelCls = ' col-lg-' + this.labellg;
30577 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30580 if(this.labelmd > 0){
30581 labelCls = ' col-md-' + this.labelmd;
30582 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30585 if(this.labelsm > 0){
30586 labelCls = ' col-sm-' + this.labelsm;
30587 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30590 if(this.labelxs > 0){
30591 labelCls = ' col-xs-' + this.labelxs;
30592 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30596 label.cls += ' ' + labelCls;
30598 cfg.cn.push(label);
30601 Roo.each(['day', 'month', 'year'], function(t){
30604 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30611 inputEl: function ()
30613 return this.el.select('.roo-date-split-field-group-value', true).first();
30616 onRender : function(ct, position)
30620 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30622 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30624 this.dayField = new Roo.bootstrap.ComboBox({
30625 allowBlank : this.dayAllowBlank,
30626 alwaysQuery : true,
30627 displayField : 'value',
30630 forceSelection : true,
30632 placeholder : this.dayPlaceholder,
30633 selectOnFocus : true,
30634 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30635 triggerAction : 'all',
30637 valueField : 'value',
30638 store : new Roo.data.SimpleStore({
30639 data : (function() {
30641 _this.fireEvent('days', _this, days);
30644 fields : [ 'value' ]
30647 select : function (_self, record, index)
30649 _this.setValue(_this.getValue());
30654 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30656 this.monthField = new Roo.bootstrap.MonthField({
30657 after : '<i class=\"fa fa-calendar\"></i>',
30658 allowBlank : this.monthAllowBlank,
30659 placeholder : this.monthPlaceholder,
30662 render : function (_self)
30664 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30665 e.preventDefault();
30669 select : function (_self, oldvalue, newvalue)
30671 _this.setValue(_this.getValue());
30676 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30678 this.yearField = new Roo.bootstrap.ComboBox({
30679 allowBlank : this.yearAllowBlank,
30680 alwaysQuery : true,
30681 displayField : 'value',
30684 forceSelection : true,
30686 placeholder : this.yearPlaceholder,
30687 selectOnFocus : true,
30688 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30689 triggerAction : 'all',
30691 valueField : 'value',
30692 store : new Roo.data.SimpleStore({
30693 data : (function() {
30695 _this.fireEvent('years', _this, years);
30698 fields : [ 'value' ]
30701 select : function (_self, record, index)
30703 _this.setValue(_this.getValue());
30708 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30711 setValue : function(v, format)
30713 this.inputEl.dom.value = v;
30715 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30717 var d = Date.parseDate(v, f);
30724 this.setDay(d.format(this.dayFormat));
30725 this.setMonth(d.format(this.monthFormat));
30726 this.setYear(d.format(this.yearFormat));
30733 setDay : function(v)
30735 this.dayField.setValue(v);
30736 this.inputEl.dom.value = this.getValue();
30741 setMonth : function(v)
30743 this.monthField.setValue(v, true);
30744 this.inputEl.dom.value = this.getValue();
30749 setYear : function(v)
30751 this.yearField.setValue(v);
30752 this.inputEl.dom.value = this.getValue();
30757 getDay : function()
30759 return this.dayField.getValue();
30762 getMonth : function()
30764 return this.monthField.getValue();
30767 getYear : function()
30769 return this.yearField.getValue();
30772 getValue : function()
30774 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30776 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30786 this.inputEl.dom.value = '';
30791 validate : function()
30793 var d = this.dayField.validate();
30794 var m = this.monthField.validate();
30795 var y = this.yearField.validate();
30800 (!this.dayAllowBlank && !d) ||
30801 (!this.monthAllowBlank && !m) ||
30802 (!this.yearAllowBlank && !y)
30807 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30816 this.markInvalid();
30821 markValid : function()
30824 var label = this.el.select('label', true).first();
30825 var icon = this.el.select('i.fa-star', true).first();
30831 this.fireEvent('valid', this);
30835 * Mark this field as invalid
30836 * @param {String} msg The validation message
30838 markInvalid : function(msg)
30841 var label = this.el.select('label', true).first();
30842 var icon = this.el.select('i.fa-star', true).first();
30844 if(label && !icon){
30845 this.el.select('.roo-date-split-field-label', true).createChild({
30847 cls : 'text-danger fa fa-lg fa-star',
30848 tooltip : 'This field is required',
30849 style : 'margin-right:5px;'
30853 this.fireEvent('invalid', this, msg);
30856 clearInvalid : function()
30858 var label = this.el.select('label', true).first();
30859 var icon = this.el.select('i.fa-star', true).first();
30865 this.fireEvent('valid', this);
30868 getName: function()
30878 * http://masonry.desandro.com
30880 * The idea is to render all the bricks based on vertical width...
30882 * The original code extends 'outlayer' - we might need to use that....
30888 * @class Roo.bootstrap.LayoutMasonry
30889 * @extends Roo.bootstrap.Component
30890 * Bootstrap Layout Masonry class
30893 * Create a new Element
30894 * @param {Object} config The config object
30897 Roo.bootstrap.LayoutMasonry = function(config){
30899 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30903 Roo.bootstrap.LayoutMasonry.register(this);
30909 * Fire after layout the items
30910 * @param {Roo.bootstrap.LayoutMasonry} this
30911 * @param {Roo.EventObject} e
30918 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30921 * @cfg {Boolean} isLayoutInstant = no animation?
30923 isLayoutInstant : false, // needed?
30926 * @cfg {Number} boxWidth width of the columns
30931 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30936 * @cfg {Number} padWidth padding below box..
30941 * @cfg {Number} gutter gutter width..
30946 * @cfg {Number} maxCols maximum number of columns
30952 * @cfg {Boolean} isAutoInitial defalut true
30954 isAutoInitial : true,
30959 * @cfg {Boolean} isHorizontal defalut false
30961 isHorizontal : false,
30963 currentSize : null,
30969 bricks: null, //CompositeElement
30973 _isLayoutInited : false,
30975 // isAlternative : false, // only use for vertical layout...
30978 * @cfg {Number} alternativePadWidth padding below box..
30980 alternativePadWidth : 50,
30982 selectedBrick : [],
30984 getAutoCreate : function(){
30986 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30990 cls: 'blog-masonary-wrapper ' + this.cls,
30992 cls : 'mas-boxes masonary'
30999 getChildContainer: function( )
31001 if (this.boxesEl) {
31002 return this.boxesEl;
31005 this.boxesEl = this.el.select('.mas-boxes').first();
31007 return this.boxesEl;
31011 initEvents : function()
31015 if(this.isAutoInitial){
31016 Roo.log('hook children rendered');
31017 this.on('childrenrendered', function() {
31018 Roo.log('children rendered');
31024 initial : function()
31026 this.selectedBrick = [];
31028 this.currentSize = this.el.getBox(true);
31030 Roo.EventManager.onWindowResize(this.resize, this);
31032 if(!this.isAutoInitial){
31040 //this.layout.defer(500,this);
31044 resize : function()
31046 var cs = this.el.getBox(true);
31049 this.currentSize.width == cs.width &&
31050 this.currentSize.x == cs.x &&
31051 this.currentSize.height == cs.height &&
31052 this.currentSize.y == cs.y
31054 Roo.log("no change in with or X or Y");
31058 this.currentSize = cs;
31064 layout : function()
31066 this._resetLayout();
31068 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31070 this.layoutItems( isInstant );
31072 this._isLayoutInited = true;
31074 this.fireEvent('layout', this);
31078 _resetLayout : function()
31080 if(this.isHorizontal){
31081 this.horizontalMeasureColumns();
31085 this.verticalMeasureColumns();
31089 verticalMeasureColumns : function()
31091 this.getContainerWidth();
31093 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31094 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31098 var boxWidth = this.boxWidth + this.padWidth;
31100 if(this.containerWidth < this.boxWidth){
31101 boxWidth = this.containerWidth
31104 var containerWidth = this.containerWidth;
31106 var cols = Math.floor(containerWidth / boxWidth);
31108 this.cols = Math.max( cols, 1 );
31110 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31112 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31114 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31116 this.colWidth = boxWidth + avail - this.padWidth;
31118 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31119 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31122 horizontalMeasureColumns : function()
31124 this.getContainerWidth();
31126 var boxWidth = this.boxWidth;
31128 if(this.containerWidth < boxWidth){
31129 boxWidth = this.containerWidth;
31132 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31134 this.el.setHeight(boxWidth);
31138 getContainerWidth : function()
31140 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31143 layoutItems : function( isInstant )
31145 Roo.log(this.bricks);
31147 var items = Roo.apply([], this.bricks);
31149 if(this.isHorizontal){
31150 this._horizontalLayoutItems( items , isInstant );
31154 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31155 // this._verticalAlternativeLayoutItems( items , isInstant );
31159 this._verticalLayoutItems( items , isInstant );
31163 _verticalLayoutItems : function ( items , isInstant)
31165 if ( !items || !items.length ) {
31170 ['xs', 'xs', 'xs', 'tall'],
31171 ['xs', 'xs', 'tall'],
31172 ['xs', 'xs', 'sm'],
31173 ['xs', 'xs', 'xs'],
31179 ['sm', 'xs', 'xs'],
31183 ['tall', 'xs', 'xs', 'xs'],
31184 ['tall', 'xs', 'xs'],
31196 Roo.each(items, function(item, k){
31198 switch (item.size) {
31199 // these layouts take up a full box,
31210 boxes.push([item]);
31233 var filterPattern = function(box, length)
31241 var pattern = box.slice(0, length);
31245 Roo.each(pattern, function(i){
31246 format.push(i.size);
31249 Roo.each(standard, function(s){
31251 if(String(s) != String(format)){
31260 if(!match && length == 1){
31265 filterPattern(box, length - 1);
31269 queue.push(pattern);
31271 box = box.slice(length, box.length);
31273 filterPattern(box, 4);
31279 Roo.each(boxes, function(box, k){
31285 if(box.length == 1){
31290 filterPattern(box, 4);
31294 this._processVerticalLayoutQueue( queue, isInstant );
31298 // _verticalAlternativeLayoutItems : function( items , isInstant )
31300 // if ( !items || !items.length ) {
31304 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31308 _horizontalLayoutItems : function ( items , isInstant)
31310 if ( !items || !items.length || items.length < 3) {
31316 var eItems = items.slice(0, 3);
31318 items = items.slice(3, items.length);
31321 ['xs', 'xs', 'xs', 'wide'],
31322 ['xs', 'xs', 'wide'],
31323 ['xs', 'xs', 'sm'],
31324 ['xs', 'xs', 'xs'],
31330 ['sm', 'xs', 'xs'],
31334 ['wide', 'xs', 'xs', 'xs'],
31335 ['wide', 'xs', 'xs'],
31348 Roo.each(items, function(item, k){
31350 switch (item.size) {
31361 boxes.push([item]);
31385 var filterPattern = function(box, length)
31393 var pattern = box.slice(0, length);
31397 Roo.each(pattern, function(i){
31398 format.push(i.size);
31401 Roo.each(standard, function(s){
31403 if(String(s) != String(format)){
31412 if(!match && length == 1){
31417 filterPattern(box, length - 1);
31421 queue.push(pattern);
31423 box = box.slice(length, box.length);
31425 filterPattern(box, 4);
31431 Roo.each(boxes, function(box, k){
31437 if(box.length == 1){
31442 filterPattern(box, 4);
31449 var pos = this.el.getBox(true);
31453 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31455 var hit_end = false;
31457 Roo.each(queue, function(box){
31461 Roo.each(box, function(b){
31463 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31473 Roo.each(box, function(b){
31475 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31478 mx = Math.max(mx, b.x);
31482 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31486 Roo.each(box, function(b){
31488 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31502 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31505 /** Sets position of item in DOM
31506 * @param {Element} item
31507 * @param {Number} x - horizontal position
31508 * @param {Number} y - vertical position
31509 * @param {Boolean} isInstant - disables transitions
31511 _processVerticalLayoutQueue : function( queue, isInstant )
31513 var pos = this.el.getBox(true);
31518 for (var i = 0; i < this.cols; i++){
31522 Roo.each(queue, function(box, k){
31524 var col = k % this.cols;
31526 Roo.each(box, function(b,kk){
31528 b.el.position('absolute');
31530 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31531 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31533 if(b.size == 'md-left' || b.size == 'md-right'){
31534 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31535 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31538 b.el.setWidth(width);
31539 b.el.setHeight(height);
31541 b.el.select('iframe',true).setSize(width,height);
31545 for (var i = 0; i < this.cols; i++){
31547 if(maxY[i] < maxY[col]){
31552 col = Math.min(col, i);
31556 x = pos.x + col * (this.colWidth + this.padWidth);
31560 var positions = [];
31562 switch (box.length){
31564 positions = this.getVerticalOneBoxColPositions(x, y, box);
31567 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31570 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31573 positions = this.getVerticalFourBoxColPositions(x, y, box);
31579 Roo.each(box, function(b,kk){
31581 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31583 var sz = b.el.getSize();
31585 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31593 for (var i = 0; i < this.cols; i++){
31594 mY = Math.max(mY, maxY[i]);
31597 this.el.setHeight(mY - pos.y);
31601 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31603 // var pos = this.el.getBox(true);
31606 // var maxX = pos.right;
31608 // var maxHeight = 0;
31610 // Roo.each(items, function(item, k){
31614 // item.el.position('absolute');
31616 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31618 // item.el.setWidth(width);
31620 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31622 // item.el.setHeight(height);
31625 // item.el.setXY([x, y], isInstant ? false : true);
31627 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31630 // y = y + height + this.alternativePadWidth;
31632 // maxHeight = maxHeight + height + this.alternativePadWidth;
31636 // this.el.setHeight(maxHeight);
31640 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31642 var pos = this.el.getBox(true);
31647 var maxX = pos.right;
31649 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31651 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31653 Roo.each(queue, function(box, k){
31655 Roo.each(box, function(b, kk){
31657 b.el.position('absolute');
31659 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31660 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31662 if(b.size == 'md-left' || b.size == 'md-right'){
31663 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31664 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31667 b.el.setWidth(width);
31668 b.el.setHeight(height);
31676 var positions = [];
31678 switch (box.length){
31680 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31683 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31686 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31689 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31695 Roo.each(box, function(b,kk){
31697 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31699 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31707 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31709 Roo.each(eItems, function(b,k){
31711 b.size = (k == 0) ? 'sm' : 'xs';
31712 b.x = (k == 0) ? 2 : 1;
31713 b.y = (k == 0) ? 2 : 1;
31715 b.el.position('absolute');
31717 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31719 b.el.setWidth(width);
31721 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31723 b.el.setHeight(height);
31727 var positions = [];
31730 x : maxX - this.unitWidth * 2 - this.gutter,
31735 x : maxX - this.unitWidth,
31736 y : minY + (this.unitWidth + this.gutter) * 2
31740 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31744 Roo.each(eItems, function(b,k){
31746 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31752 getVerticalOneBoxColPositions : function(x, y, box)
31756 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31758 if(box[0].size == 'md-left'){
31762 if(box[0].size == 'md-right'){
31767 x : x + (this.unitWidth + this.gutter) * rand,
31774 getVerticalTwoBoxColPositions : function(x, y, box)
31778 if(box[0].size == 'xs'){
31782 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31786 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31800 x : x + (this.unitWidth + this.gutter) * 2,
31801 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31808 getVerticalThreeBoxColPositions : function(x, y, box)
31812 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31820 x : x + (this.unitWidth + this.gutter) * 1,
31825 x : x + (this.unitWidth + this.gutter) * 2,
31833 if(box[0].size == 'xs' && box[1].size == 'xs'){
31842 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31846 x : x + (this.unitWidth + this.gutter) * 1,
31860 x : x + (this.unitWidth + this.gutter) * 2,
31865 x : x + (this.unitWidth + this.gutter) * 2,
31866 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31873 getVerticalFourBoxColPositions : function(x, y, box)
31877 if(box[0].size == 'xs'){
31886 y : y + (this.unitHeight + this.gutter) * 1
31891 y : y + (this.unitHeight + this.gutter) * 2
31895 x : x + (this.unitWidth + this.gutter) * 1,
31909 x : x + (this.unitWidth + this.gutter) * 2,
31914 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31915 y : y + (this.unitHeight + this.gutter) * 1
31919 x : x + (this.unitWidth + this.gutter) * 2,
31920 y : y + (this.unitWidth + this.gutter) * 2
31927 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31931 if(box[0].size == 'md-left'){
31933 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31940 if(box[0].size == 'md-right'){
31942 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31943 y : minY + (this.unitWidth + this.gutter) * 1
31949 var rand = Math.floor(Math.random() * (4 - box[0].y));
31952 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31953 y : minY + (this.unitWidth + this.gutter) * rand
31960 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31964 if(box[0].size == 'xs'){
31967 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31972 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31973 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31981 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31986 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31987 y : minY + (this.unitWidth + this.gutter) * 2
31994 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31998 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32001 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32006 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32007 y : minY + (this.unitWidth + this.gutter) * 1
32011 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32012 y : minY + (this.unitWidth + this.gutter) * 2
32019 if(box[0].size == 'xs' && box[1].size == 'xs'){
32022 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32027 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32032 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32033 y : minY + (this.unitWidth + this.gutter) * 1
32041 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32046 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32047 y : minY + (this.unitWidth + this.gutter) * 2
32051 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32052 y : minY + (this.unitWidth + this.gutter) * 2
32059 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32063 if(box[0].size == 'xs'){
32066 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32071 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32076 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),
32081 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32082 y : minY + (this.unitWidth + this.gutter) * 1
32090 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32095 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32096 y : minY + (this.unitWidth + this.gutter) * 2
32100 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32101 y : minY + (this.unitWidth + this.gutter) * 2
32105 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),
32106 y : minY + (this.unitWidth + this.gutter) * 2
32114 * remove a Masonry Brick
32115 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32117 removeBrick : function(brick_id)
32123 for (var i = 0; i<this.bricks.length; i++) {
32124 if (this.bricks[i].id == brick_id) {
32125 this.bricks.splice(i,1);
32126 this.el.dom.removeChild(Roo.get(brick_id).dom);
32133 * adds a Masonry Brick
32134 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32136 addBrick : function(cfg)
32138 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32139 //this.register(cn);
32140 cn.parentId = this.id;
32141 cn.render(this.el);
32146 * register a Masonry Brick
32147 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32150 register : function(brick)
32152 this.bricks.push(brick);
32153 brick.masonryId = this.id;
32157 * clear all the Masonry Brick
32159 clearAll : function()
32162 //this.getChildContainer().dom.innerHTML = "";
32163 this.el.dom.innerHTML = '';
32166 getSelected : function()
32168 if (!this.selectedBrick) {
32172 return this.selectedBrick;
32176 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32180 * register a Masonry Layout
32181 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32184 register : function(layout)
32186 this.groups[layout.id] = layout;
32189 * fetch a Masonry Layout based on the masonry layout ID
32190 * @param {string} the masonry layout to add
32191 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32194 get: function(layout_id) {
32195 if (typeof(this.groups[layout_id]) == 'undefined') {
32198 return this.groups[layout_id] ;
32210 * http://masonry.desandro.com
32212 * The idea is to render all the bricks based on vertical width...
32214 * The original code extends 'outlayer' - we might need to use that....
32220 * @class Roo.bootstrap.LayoutMasonryAuto
32221 * @extends Roo.bootstrap.Component
32222 * Bootstrap Layout Masonry class
32225 * Create a new Element
32226 * @param {Object} config The config object
32229 Roo.bootstrap.LayoutMasonryAuto = function(config){
32230 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32233 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32236 * @cfg {Boolean} isFitWidth - resize the width..
32238 isFitWidth : false, // options..
32240 * @cfg {Boolean} isOriginLeft = left align?
32242 isOriginLeft : true,
32244 * @cfg {Boolean} isOriginTop = top align?
32246 isOriginTop : false,
32248 * @cfg {Boolean} isLayoutInstant = no animation?
32250 isLayoutInstant : false, // needed?
32252 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32254 isResizingContainer : true,
32256 * @cfg {Number} columnWidth width of the columns
32262 * @cfg {Number} maxCols maximum number of columns
32267 * @cfg {Number} padHeight padding below box..
32273 * @cfg {Boolean} isAutoInitial defalut true
32276 isAutoInitial : true,
32282 initialColumnWidth : 0,
32283 currentSize : null,
32285 colYs : null, // array.
32292 bricks: null, //CompositeElement
32293 cols : 0, // array?
32294 // element : null, // wrapped now this.el
32295 _isLayoutInited : null,
32298 getAutoCreate : function(){
32302 cls: 'blog-masonary-wrapper ' + this.cls,
32304 cls : 'mas-boxes masonary'
32311 getChildContainer: function( )
32313 if (this.boxesEl) {
32314 return this.boxesEl;
32317 this.boxesEl = this.el.select('.mas-boxes').first();
32319 return this.boxesEl;
32323 initEvents : function()
32327 if(this.isAutoInitial){
32328 Roo.log('hook children rendered');
32329 this.on('childrenrendered', function() {
32330 Roo.log('children rendered');
32337 initial : function()
32339 this.reloadItems();
32341 this.currentSize = this.el.getBox(true);
32343 /// was window resize... - let's see if this works..
32344 Roo.EventManager.onWindowResize(this.resize, this);
32346 if(!this.isAutoInitial){
32351 this.layout.defer(500,this);
32354 reloadItems: function()
32356 this.bricks = this.el.select('.masonry-brick', true);
32358 this.bricks.each(function(b) {
32359 //Roo.log(b.getSize());
32360 if (!b.attr('originalwidth')) {
32361 b.attr('originalwidth', b.getSize().width);
32366 Roo.log(this.bricks.elements.length);
32369 resize : function()
32372 var cs = this.el.getBox(true);
32374 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32375 Roo.log("no change in with or X");
32378 this.currentSize = cs;
32382 layout : function()
32385 this._resetLayout();
32386 //this._manageStamps();
32388 // don't animate first layout
32389 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32390 this.layoutItems( isInstant );
32392 // flag for initalized
32393 this._isLayoutInited = true;
32396 layoutItems : function( isInstant )
32398 //var items = this._getItemsForLayout( this.items );
32399 // original code supports filtering layout items.. we just ignore it..
32401 this._layoutItems( this.bricks , isInstant );
32403 this._postLayout();
32405 _layoutItems : function ( items , isInstant)
32407 //this.fireEvent( 'layout', this, items );
32410 if ( !items || !items.elements.length ) {
32411 // no items, emit event with empty array
32416 items.each(function(item) {
32417 Roo.log("layout item");
32419 // get x/y object from method
32420 var position = this._getItemLayoutPosition( item );
32422 position.item = item;
32423 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32424 queue.push( position );
32427 this._processLayoutQueue( queue );
32429 /** Sets position of item in DOM
32430 * @param {Element} item
32431 * @param {Number} x - horizontal position
32432 * @param {Number} y - vertical position
32433 * @param {Boolean} isInstant - disables transitions
32435 _processLayoutQueue : function( queue )
32437 for ( var i=0, len = queue.length; i < len; i++ ) {
32438 var obj = queue[i];
32439 obj.item.position('absolute');
32440 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32446 * Any logic you want to do after each layout,
32447 * i.e. size the container
32449 _postLayout : function()
32451 this.resizeContainer();
32454 resizeContainer : function()
32456 if ( !this.isResizingContainer ) {
32459 var size = this._getContainerSize();
32461 this.el.setSize(size.width,size.height);
32462 this.boxesEl.setSize(size.width,size.height);
32468 _resetLayout : function()
32470 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32471 this.colWidth = this.el.getWidth();
32472 //this.gutter = this.el.getWidth();
32474 this.measureColumns();
32480 this.colYs.push( 0 );
32486 measureColumns : function()
32488 this.getContainerWidth();
32489 // if columnWidth is 0, default to outerWidth of first item
32490 if ( !this.columnWidth ) {
32491 var firstItem = this.bricks.first();
32492 Roo.log(firstItem);
32493 this.columnWidth = this.containerWidth;
32494 if (firstItem && firstItem.attr('originalwidth') ) {
32495 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32497 // columnWidth fall back to item of first element
32498 Roo.log("set column width?");
32499 this.initialColumnWidth = this.columnWidth ;
32501 // if first elem has no width, default to size of container
32506 if (this.initialColumnWidth) {
32507 this.columnWidth = this.initialColumnWidth;
32512 // column width is fixed at the top - however if container width get's smaller we should
32515 // this bit calcs how man columns..
32517 var columnWidth = this.columnWidth += this.gutter;
32519 // calculate columns
32520 var containerWidth = this.containerWidth + this.gutter;
32522 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32523 // fix rounding errors, typically with gutters
32524 var excess = columnWidth - containerWidth % columnWidth;
32527 // if overshoot is less than a pixel, round up, otherwise floor it
32528 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32529 cols = Math[ mathMethod ]( cols );
32530 this.cols = Math.max( cols, 1 );
32531 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32533 // padding positioning..
32534 var totalColWidth = this.cols * this.columnWidth;
32535 var padavail = this.containerWidth - totalColWidth;
32536 // so for 2 columns - we need 3 'pads'
32538 var padNeeded = (1+this.cols) * this.padWidth;
32540 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32542 this.columnWidth += padExtra
32543 //this.padWidth = Math.floor(padavail / ( this.cols));
32545 // adjust colum width so that padding is fixed??
32547 // we have 3 columns ... total = width * 3
32548 // we have X left over... that should be used by
32550 //if (this.expandC) {
32558 getContainerWidth : function()
32560 /* // container is parent if fit width
32561 var container = this.isFitWidth ? this.element.parentNode : this.element;
32562 // check that this.size and size are there
32563 // IE8 triggers resize on body size change, so they might not be
32565 var size = getSize( container ); //FIXME
32566 this.containerWidth = size && size.innerWidth; //FIXME
32569 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32573 _getItemLayoutPosition : function( item ) // what is item?
32575 // we resize the item to our columnWidth..
32577 item.setWidth(this.columnWidth);
32578 item.autoBoxAdjust = false;
32580 var sz = item.getSize();
32582 // how many columns does this brick span
32583 var remainder = this.containerWidth % this.columnWidth;
32585 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32586 // round if off by 1 pixel, otherwise use ceil
32587 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32588 colSpan = Math.min( colSpan, this.cols );
32590 // normally this should be '1' as we dont' currently allow multi width columns..
32592 var colGroup = this._getColGroup( colSpan );
32593 // get the minimum Y value from the columns
32594 var minimumY = Math.min.apply( Math, colGroup );
32595 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32597 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32599 // position the brick
32601 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32602 y: this.currentSize.y + minimumY + this.padHeight
32606 // apply setHeight to necessary columns
32607 var setHeight = minimumY + sz.height + this.padHeight;
32608 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32610 var setSpan = this.cols + 1 - colGroup.length;
32611 for ( var i = 0; i < setSpan; i++ ) {
32612 this.colYs[ shortColIndex + i ] = setHeight ;
32619 * @param {Number} colSpan - number of columns the element spans
32620 * @returns {Array} colGroup
32622 _getColGroup : function( colSpan )
32624 if ( colSpan < 2 ) {
32625 // if brick spans only one column, use all the column Ys
32630 // how many different places could this brick fit horizontally
32631 var groupCount = this.cols + 1 - colSpan;
32632 // for each group potential horizontal position
32633 for ( var i = 0; i < groupCount; i++ ) {
32634 // make an array of colY values for that one group
32635 var groupColYs = this.colYs.slice( i, i + colSpan );
32636 // and get the max value of the array
32637 colGroup[i] = Math.max.apply( Math, groupColYs );
32642 _manageStamp : function( stamp )
32644 var stampSize = stamp.getSize();
32645 var offset = stamp.getBox();
32646 // get the columns that this stamp affects
32647 var firstX = this.isOriginLeft ? offset.x : offset.right;
32648 var lastX = firstX + stampSize.width;
32649 var firstCol = Math.floor( firstX / this.columnWidth );
32650 firstCol = Math.max( 0, firstCol );
32652 var lastCol = Math.floor( lastX / this.columnWidth );
32653 // lastCol should not go over if multiple of columnWidth #425
32654 lastCol -= lastX % this.columnWidth ? 0 : 1;
32655 lastCol = Math.min( this.cols - 1, lastCol );
32657 // set colYs to bottom of the stamp
32658 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32661 for ( var i = firstCol; i <= lastCol; i++ ) {
32662 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32667 _getContainerSize : function()
32669 this.maxY = Math.max.apply( Math, this.colYs );
32674 if ( this.isFitWidth ) {
32675 size.width = this._getContainerFitWidth();
32681 _getContainerFitWidth : function()
32683 var unusedCols = 0;
32684 // count unused columns
32687 if ( this.colYs[i] !== 0 ) {
32692 // fit container to columns that have been used
32693 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32696 needsResizeLayout : function()
32698 var previousWidth = this.containerWidth;
32699 this.getContainerWidth();
32700 return previousWidth !== this.containerWidth;
32715 * @class Roo.bootstrap.MasonryBrick
32716 * @extends Roo.bootstrap.Component
32717 * Bootstrap MasonryBrick class
32720 * Create a new MasonryBrick
32721 * @param {Object} config The config object
32724 Roo.bootstrap.MasonryBrick = function(config){
32726 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32728 Roo.bootstrap.MasonryBrick.register(this);
32734 * When a MasonryBrick is clcik
32735 * @param {Roo.bootstrap.MasonryBrick} this
32736 * @param {Roo.EventObject} e
32742 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32745 * @cfg {String} title
32749 * @cfg {String} html
32753 * @cfg {String} bgimage
32757 * @cfg {String} videourl
32761 * @cfg {String} cls
32765 * @cfg {String} href
32769 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32774 * @cfg {String} placetitle (center|bottom)
32779 * @cfg {Boolean} isFitContainer defalut true
32781 isFitContainer : true,
32784 * @cfg {Boolean} preventDefault defalut false
32786 preventDefault : false,
32789 * @cfg {Boolean} inverse defalut false
32791 maskInverse : false,
32793 getAutoCreate : function()
32795 if(!this.isFitContainer){
32796 return this.getSplitAutoCreate();
32799 var cls = 'masonry-brick masonry-brick-full';
32801 if(this.href.length){
32802 cls += ' masonry-brick-link';
32805 if(this.bgimage.length){
32806 cls += ' masonry-brick-image';
32809 if(this.maskInverse){
32810 cls += ' mask-inverse';
32813 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32814 cls += ' enable-mask';
32818 cls += ' masonry-' + this.size + '-brick';
32821 if(this.placetitle.length){
32823 switch (this.placetitle) {
32825 cls += ' masonry-center-title';
32828 cls += ' masonry-bottom-title';
32835 if(!this.html.length && !this.bgimage.length){
32836 cls += ' masonry-center-title';
32839 if(!this.html.length && this.bgimage.length){
32840 cls += ' masonry-bottom-title';
32845 cls += ' ' + this.cls;
32849 tag: (this.href.length) ? 'a' : 'div',
32854 cls: 'masonry-brick-mask'
32858 cls: 'masonry-brick-paragraph',
32864 if(this.href.length){
32865 cfg.href = this.href;
32868 var cn = cfg.cn[1].cn;
32870 if(this.title.length){
32873 cls: 'masonry-brick-title',
32878 if(this.html.length){
32881 cls: 'masonry-brick-text',
32886 if (!this.title.length && !this.html.length) {
32887 cfg.cn[1].cls += ' hide';
32890 if(this.bgimage.length){
32893 cls: 'masonry-brick-image-view',
32898 if(this.videourl.length){
32899 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32900 // youtube support only?
32903 cls: 'masonry-brick-image-view',
32906 allowfullscreen : true
32914 getSplitAutoCreate : function()
32916 var cls = 'masonry-brick masonry-brick-split';
32918 if(this.href.length){
32919 cls += ' masonry-brick-link';
32922 if(this.bgimage.length){
32923 cls += ' masonry-brick-image';
32927 cls += ' masonry-' + this.size + '-brick';
32930 switch (this.placetitle) {
32932 cls += ' masonry-center-title';
32935 cls += ' masonry-bottom-title';
32938 if(!this.bgimage.length){
32939 cls += ' masonry-center-title';
32942 if(this.bgimage.length){
32943 cls += ' masonry-bottom-title';
32949 cls += ' ' + this.cls;
32953 tag: (this.href.length) ? 'a' : 'div',
32958 cls: 'masonry-brick-split-head',
32962 cls: 'masonry-brick-paragraph',
32969 cls: 'masonry-brick-split-body',
32975 if(this.href.length){
32976 cfg.href = this.href;
32979 if(this.title.length){
32980 cfg.cn[0].cn[0].cn.push({
32982 cls: 'masonry-brick-title',
32987 if(this.html.length){
32988 cfg.cn[1].cn.push({
32990 cls: 'masonry-brick-text',
32995 if(this.bgimage.length){
32996 cfg.cn[0].cn.push({
32998 cls: 'masonry-brick-image-view',
33003 if(this.videourl.length){
33004 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33005 // youtube support only?
33006 cfg.cn[0].cn.cn.push({
33008 cls: 'masonry-brick-image-view',
33011 allowfullscreen : true
33018 initEvents: function()
33020 switch (this.size) {
33053 this.el.on('touchstart', this.onTouchStart, this);
33054 this.el.on('touchmove', this.onTouchMove, this);
33055 this.el.on('touchend', this.onTouchEnd, this);
33056 this.el.on('contextmenu', this.onContextMenu, this);
33058 this.el.on('mouseenter' ,this.enter, this);
33059 this.el.on('mouseleave', this.leave, this);
33060 this.el.on('click', this.onClick, this);
33063 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33064 this.parent().bricks.push(this);
33069 onClick: function(e, el)
33071 var time = this.endTimer - this.startTimer;
33072 // Roo.log(e.preventDefault());
33075 e.preventDefault();
33080 if(!this.preventDefault){
33084 e.preventDefault();
33086 if (this.activeClass != '') {
33087 this.selectBrick();
33090 this.fireEvent('click', this, e);
33093 enter: function(e, el)
33095 e.preventDefault();
33097 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33101 if(this.bgimage.length && this.html.length){
33102 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33106 leave: function(e, el)
33108 e.preventDefault();
33110 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33114 if(this.bgimage.length && this.html.length){
33115 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33119 onTouchStart: function(e, el)
33121 // e.preventDefault();
33123 this.touchmoved = false;
33125 if(!this.isFitContainer){
33129 if(!this.bgimage.length || !this.html.length){
33133 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33135 this.timer = new Date().getTime();
33139 onTouchMove: function(e, el)
33141 this.touchmoved = true;
33144 onContextMenu : function(e,el)
33146 e.preventDefault();
33147 e.stopPropagation();
33151 onTouchEnd: function(e, el)
33153 // e.preventDefault();
33155 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33162 if(!this.bgimage.length || !this.html.length){
33164 if(this.href.length){
33165 window.location.href = this.href;
33171 if(!this.isFitContainer){
33175 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33177 window.location.href = this.href;
33180 //selection on single brick only
33181 selectBrick : function() {
33183 if (!this.parentId) {
33187 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33188 var index = m.selectedBrick.indexOf(this.id);
33191 m.selectedBrick.splice(index,1);
33192 this.el.removeClass(this.activeClass);
33196 for(var i = 0; i < m.selectedBrick.length; i++) {
33197 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33198 b.el.removeClass(b.activeClass);
33201 m.selectedBrick = [];
33203 m.selectedBrick.push(this.id);
33204 this.el.addClass(this.activeClass);
33208 isSelected : function(){
33209 return this.el.hasClass(this.activeClass);
33214 Roo.apply(Roo.bootstrap.MasonryBrick, {
33217 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33219 * register a Masonry Brick
33220 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33223 register : function(brick)
33225 //this.groups[brick.id] = brick;
33226 this.groups.add(brick.id, brick);
33229 * fetch a masonry brick based on the masonry brick ID
33230 * @param {string} the masonry brick to add
33231 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33234 get: function(brick_id)
33236 // if (typeof(this.groups[brick_id]) == 'undefined') {
33239 // return this.groups[brick_id] ;
33241 if(this.groups.key(brick_id)) {
33242 return this.groups.key(brick_id);
33260 * @class Roo.bootstrap.Brick
33261 * @extends Roo.bootstrap.Component
33262 * Bootstrap Brick class
33265 * Create a new Brick
33266 * @param {Object} config The config object
33269 Roo.bootstrap.Brick = function(config){
33270 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33276 * When a Brick is click
33277 * @param {Roo.bootstrap.Brick} this
33278 * @param {Roo.EventObject} e
33284 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33287 * @cfg {String} title
33291 * @cfg {String} html
33295 * @cfg {String} bgimage
33299 * @cfg {String} cls
33303 * @cfg {String} href
33307 * @cfg {String} video
33311 * @cfg {Boolean} square
33315 getAutoCreate : function()
33317 var cls = 'roo-brick';
33319 if(this.href.length){
33320 cls += ' roo-brick-link';
33323 if(this.bgimage.length){
33324 cls += ' roo-brick-image';
33327 if(!this.html.length && !this.bgimage.length){
33328 cls += ' roo-brick-center-title';
33331 if(!this.html.length && this.bgimage.length){
33332 cls += ' roo-brick-bottom-title';
33336 cls += ' ' + this.cls;
33340 tag: (this.href.length) ? 'a' : 'div',
33345 cls: 'roo-brick-paragraph',
33351 if(this.href.length){
33352 cfg.href = this.href;
33355 var cn = cfg.cn[0].cn;
33357 if(this.title.length){
33360 cls: 'roo-brick-title',
33365 if(this.html.length){
33368 cls: 'roo-brick-text',
33375 if(this.bgimage.length){
33378 cls: 'roo-brick-image-view',
33386 initEvents: function()
33388 if(this.title.length || this.html.length){
33389 this.el.on('mouseenter' ,this.enter, this);
33390 this.el.on('mouseleave', this.leave, this);
33393 Roo.EventManager.onWindowResize(this.resize, this);
33395 if(this.bgimage.length){
33396 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33397 this.imageEl.on('load', this.onImageLoad, this);
33404 onImageLoad : function()
33409 resize : function()
33411 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33413 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33415 if(this.bgimage.length){
33416 var image = this.el.select('.roo-brick-image-view', true).first();
33418 image.setWidth(paragraph.getWidth());
33421 image.setHeight(paragraph.getWidth());
33424 this.el.setHeight(image.getHeight());
33425 paragraph.setHeight(image.getHeight());
33431 enter: function(e, el)
33433 e.preventDefault();
33435 if(this.bgimage.length){
33436 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33437 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33441 leave: function(e, el)
33443 e.preventDefault();
33445 if(this.bgimage.length){
33446 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33447 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33462 * @class Roo.bootstrap.NumberField
33463 * @extends Roo.bootstrap.Input
33464 * Bootstrap NumberField class
33470 * Create a new NumberField
33471 * @param {Object} config The config object
33474 Roo.bootstrap.NumberField = function(config){
33475 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33478 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33481 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33483 allowDecimals : true,
33485 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33487 decimalSeparator : ".",
33489 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33491 decimalPrecision : 2,
33493 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33495 allowNegative : true,
33498 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33502 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33504 minValue : Number.NEGATIVE_INFINITY,
33506 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33508 maxValue : Number.MAX_VALUE,
33510 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33512 minText : "The minimum value for this field is {0}",
33514 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33516 maxText : "The maximum value for this field is {0}",
33518 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33519 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33521 nanText : "{0} is not a valid number",
33523 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33525 thousandsDelimiter : false,
33527 * @cfg {String} valueAlign alignment of value
33529 valueAlign : "left",
33531 getAutoCreate : function()
33533 var hiddenInput = {
33537 cls: 'hidden-number-input'
33541 hiddenInput.name = this.name;
33546 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33548 this.name = hiddenInput.name;
33550 if(cfg.cn.length > 0) {
33551 cfg.cn.push(hiddenInput);
33558 initEvents : function()
33560 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33562 var allowed = "0123456789";
33564 if(this.allowDecimals){
33565 allowed += this.decimalSeparator;
33568 if(this.allowNegative){
33572 if(this.thousandsDelimiter) {
33576 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33578 var keyPress = function(e){
33580 var k = e.getKey();
33582 var c = e.getCharCode();
33585 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33586 allowed.indexOf(String.fromCharCode(c)) === -1
33592 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33596 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33601 this.el.on("keypress", keyPress, this);
33604 validateValue : function(value)
33607 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33611 var num = this.parseValue(value);
33614 this.markInvalid(String.format(this.nanText, value));
33618 if(num < this.minValue){
33619 this.markInvalid(String.format(this.minText, this.minValue));
33623 if(num > this.maxValue){
33624 this.markInvalid(String.format(this.maxText, this.maxValue));
33631 getValue : function()
33633 var v = this.hiddenEl().getValue();
33635 return this.fixPrecision(this.parseValue(v));
33638 parseValue : function(value)
33640 if(this.thousandsDelimiter) {
33642 r = new RegExp(",", "g");
33643 value = value.replace(r, "");
33646 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33647 return isNaN(value) ? '' : value;
33650 fixPrecision : function(value)
33652 if(this.thousandsDelimiter) {
33654 r = new RegExp(",", "g");
33655 value = value.replace(r, "");
33658 var nan = isNaN(value);
33660 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33661 return nan ? '' : value;
33663 return parseFloat(value).toFixed(this.decimalPrecision);
33666 setValue : function(v)
33668 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33674 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33676 this.inputEl().dom.value = (v == '') ? '' :
33677 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33679 if(!this.allowZero && v === '0') {
33680 this.hiddenEl().dom.value = '';
33681 this.inputEl().dom.value = '';
33688 decimalPrecisionFcn : function(v)
33690 return Math.floor(v);
33693 beforeBlur : function()
33695 var v = this.parseValue(this.getRawValue());
33697 if(v || v === 0 || v === ''){
33702 hiddenEl : function()
33704 return this.el.select('input.hidden-number-input',true).first();
33716 * @class Roo.bootstrap.DocumentSlider
33717 * @extends Roo.bootstrap.Component
33718 * Bootstrap DocumentSlider class
33721 * Create a new DocumentViewer
33722 * @param {Object} config The config object
33725 Roo.bootstrap.DocumentSlider = function(config){
33726 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33733 * Fire after initEvent
33734 * @param {Roo.bootstrap.DocumentSlider} this
33739 * Fire after update
33740 * @param {Roo.bootstrap.DocumentSlider} this
33746 * @param {Roo.bootstrap.DocumentSlider} this
33752 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33758 getAutoCreate : function()
33762 cls : 'roo-document-slider',
33766 cls : 'roo-document-slider-header',
33770 cls : 'roo-document-slider-header-title'
33776 cls : 'roo-document-slider-body',
33780 cls : 'roo-document-slider-prev',
33784 cls : 'fa fa-chevron-left'
33790 cls : 'roo-document-slider-thumb',
33794 cls : 'roo-document-slider-image'
33800 cls : 'roo-document-slider-next',
33804 cls : 'fa fa-chevron-right'
33816 initEvents : function()
33818 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33819 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33821 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33822 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33824 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33825 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33827 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33828 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33830 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33831 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33833 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33834 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33836 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33837 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33839 this.thumbEl.on('click', this.onClick, this);
33841 this.prevIndicator.on('click', this.prev, this);
33843 this.nextIndicator.on('click', this.next, this);
33847 initial : function()
33849 if(this.files.length){
33850 this.indicator = 1;
33854 this.fireEvent('initial', this);
33857 update : function()
33859 this.imageEl.attr('src', this.files[this.indicator - 1]);
33861 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33863 this.prevIndicator.show();
33865 if(this.indicator == 1){
33866 this.prevIndicator.hide();
33869 this.nextIndicator.show();
33871 if(this.indicator == this.files.length){
33872 this.nextIndicator.hide();
33875 this.thumbEl.scrollTo('top');
33877 this.fireEvent('update', this);
33880 onClick : function(e)
33882 e.preventDefault();
33884 this.fireEvent('click', this);
33889 e.preventDefault();
33891 this.indicator = Math.max(1, this.indicator - 1);
33898 e.preventDefault();
33900 this.indicator = Math.min(this.files.length, this.indicator + 1);
33914 * @class Roo.bootstrap.RadioSet
33915 * @extends Roo.bootstrap.Input
33916 * Bootstrap RadioSet class
33917 * @cfg {String} indicatorpos (left|right) default left
33918 * @cfg {Boolean} inline (true|false) inline the element (default true)
33919 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33921 * Create a new RadioSet
33922 * @param {Object} config The config object
33925 Roo.bootstrap.RadioSet = function(config){
33927 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33931 Roo.bootstrap.RadioSet.register(this);
33936 * Fires when the element is checked or unchecked.
33937 * @param {Roo.bootstrap.RadioSet} this This radio
33938 * @param {Roo.bootstrap.Radio} item The checked item
33943 * Fires when the element is click.
33944 * @param {Roo.bootstrap.RadioSet} this This radio set
33945 * @param {Roo.bootstrap.Radio} item The checked item
33946 * @param {Roo.EventObject} e The event object
33953 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33961 indicatorpos : 'left',
33963 getAutoCreate : function()
33967 cls : 'roo-radio-set-label',
33971 html : this.fieldLabel
33976 if(this.indicatorpos == 'left'){
33979 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33980 tooltip : 'This field is required'
33985 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33986 tooltip : 'This field is required'
33992 cls : 'roo-radio-set-items'
33995 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33997 if (align === 'left' && this.fieldLabel.length) {
34000 cls : "roo-radio-set-right",
34006 if(this.labelWidth > 12){
34007 label.style = "width: " + this.labelWidth + 'px';
34010 if(this.labelWidth < 13 && this.labelmd == 0){
34011 this.labelmd = this.labelWidth;
34014 if(this.labellg > 0){
34015 label.cls += ' col-lg-' + this.labellg;
34016 items.cls += ' col-lg-' + (12 - this.labellg);
34019 if(this.labelmd > 0){
34020 label.cls += ' col-md-' + this.labelmd;
34021 items.cls += ' col-md-' + (12 - this.labelmd);
34024 if(this.labelsm > 0){
34025 label.cls += ' col-sm-' + this.labelsm;
34026 items.cls += ' col-sm-' + (12 - this.labelsm);
34029 if(this.labelxs > 0){
34030 label.cls += ' col-xs-' + this.labelxs;
34031 items.cls += ' col-xs-' + (12 - this.labelxs);
34037 cls : 'roo-radio-set',
34041 cls : 'roo-radio-set-input',
34044 value : this.value ? this.value : ''
34051 if(this.weight.length){
34052 cfg.cls += ' roo-radio-' + this.weight;
34056 cfg.cls += ' roo-radio-set-inline';
34060 ['xs','sm','md','lg'].map(function(size){
34061 if (settings[size]) {
34062 cfg.cls += ' col-' + size + '-' + settings[size];
34070 initEvents : function()
34072 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34073 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34075 if(!this.fieldLabel.length){
34076 this.labelEl.hide();
34079 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34080 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34082 this.indicator = this.indicatorEl();
34084 if(this.indicator){
34085 this.indicator.addClass('invisible');
34088 this.originalValue = this.getValue();
34092 inputEl: function ()
34094 return this.el.select('.roo-radio-set-input', true).first();
34097 getChildContainer : function()
34099 return this.itemsEl;
34102 register : function(item)
34104 this.radioes.push(item);
34108 validate : function()
34110 if(this.getVisibilityEl().hasClass('hidden')){
34116 Roo.each(this.radioes, function(i){
34125 if(this.allowBlank) {
34129 if(this.disabled || valid){
34134 this.markInvalid();
34139 markValid : function()
34141 if(this.labelEl.isVisible(true)){
34142 this.indicatorEl().removeClass('visible');
34143 this.indicatorEl().addClass('invisible');
34146 this.el.removeClass([this.invalidClass, this.validClass]);
34147 this.el.addClass(this.validClass);
34149 this.fireEvent('valid', this);
34152 markInvalid : function(msg)
34154 if(this.allowBlank || this.disabled){
34158 if(this.labelEl.isVisible(true)){
34159 this.indicatorEl().removeClass('invisible');
34160 this.indicatorEl().addClass('visible');
34163 this.el.removeClass([this.invalidClass, this.validClass]);
34164 this.el.addClass(this.invalidClass);
34166 this.fireEvent('invalid', this, msg);
34170 setValue : function(v, suppressEvent)
34172 if(this.value === v){
34179 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34182 Roo.each(this.radioes, function(i){
34184 i.el.removeClass('checked');
34187 Roo.each(this.radioes, function(i){
34189 if(i.value === v || i.value.toString() === v.toString()){
34191 i.el.addClass('checked');
34193 if(suppressEvent !== true){
34194 this.fireEvent('check', this, i);
34205 clearInvalid : function(){
34207 if(!this.el || this.preventMark){
34211 this.el.removeClass([this.invalidClass]);
34213 this.fireEvent('valid', this);
34218 Roo.apply(Roo.bootstrap.RadioSet, {
34222 register : function(set)
34224 this.groups[set.name] = set;
34227 get: function(name)
34229 if (typeof(this.groups[name]) == 'undefined') {
34233 return this.groups[name] ;
34239 * Ext JS Library 1.1.1
34240 * Copyright(c) 2006-2007, Ext JS, LLC.
34242 * Originally Released Under LGPL - original licence link has changed is not relivant.
34245 * <script type="text/javascript">
34250 * @class Roo.bootstrap.SplitBar
34251 * @extends Roo.util.Observable
34252 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34256 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34257 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34258 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34259 split.minSize = 100;
34260 split.maxSize = 600;
34261 split.animate = true;
34262 split.on('moved', splitterMoved);
34265 * Create a new SplitBar
34266 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34267 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34268 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34269 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34270 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34271 position of the SplitBar).
34273 Roo.bootstrap.SplitBar = function(cfg){
34278 // dragElement : elm
34279 // resizingElement: el,
34281 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34282 // placement : Roo.bootstrap.SplitBar.LEFT ,
34283 // existingProxy ???
34286 this.el = Roo.get(cfg.dragElement, true);
34287 this.el.dom.unselectable = "on";
34289 this.resizingEl = Roo.get(cfg.resizingElement, true);
34293 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34294 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34297 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34300 * The minimum size of the resizing element. (Defaults to 0)
34306 * The maximum size of the resizing element. (Defaults to 2000)
34309 this.maxSize = 2000;
34312 * Whether to animate the transition to the new size
34315 this.animate = false;
34318 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34321 this.useShim = false;
34326 if(!cfg.existingProxy){
34328 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34330 this.proxy = Roo.get(cfg.existingProxy).dom;
34333 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34336 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34339 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34342 this.dragSpecs = {};
34345 * @private The adapter to use to positon and resize elements
34347 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34348 this.adapter.init(this);
34350 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34352 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34353 this.el.addClass("roo-splitbar-h");
34356 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34357 this.el.addClass("roo-splitbar-v");
34363 * Fires when the splitter is moved (alias for {@link #event-moved})
34364 * @param {Roo.bootstrap.SplitBar} this
34365 * @param {Number} newSize the new width or height
34370 * Fires when the splitter is moved
34371 * @param {Roo.bootstrap.SplitBar} this
34372 * @param {Number} newSize the new width or height
34376 * @event beforeresize
34377 * Fires before the splitter is dragged
34378 * @param {Roo.bootstrap.SplitBar} this
34380 "beforeresize" : true,
34382 "beforeapply" : true
34385 Roo.util.Observable.call(this);
34388 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34389 onStartProxyDrag : function(x, y){
34390 this.fireEvent("beforeresize", this);
34392 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34394 o.enableDisplayMode("block");
34395 // all splitbars share the same overlay
34396 Roo.bootstrap.SplitBar.prototype.overlay = o;
34398 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34399 this.overlay.show();
34400 Roo.get(this.proxy).setDisplayed("block");
34401 var size = this.adapter.getElementSize(this);
34402 this.activeMinSize = this.getMinimumSize();;
34403 this.activeMaxSize = this.getMaximumSize();;
34404 var c1 = size - this.activeMinSize;
34405 var c2 = Math.max(this.activeMaxSize - size, 0);
34406 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34407 this.dd.resetConstraints();
34408 this.dd.setXConstraint(
34409 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34410 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34412 this.dd.setYConstraint(0, 0);
34414 this.dd.resetConstraints();
34415 this.dd.setXConstraint(0, 0);
34416 this.dd.setYConstraint(
34417 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34418 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34421 this.dragSpecs.startSize = size;
34422 this.dragSpecs.startPoint = [x, y];
34423 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34427 * @private Called after the drag operation by the DDProxy
34429 onEndProxyDrag : function(e){
34430 Roo.get(this.proxy).setDisplayed(false);
34431 var endPoint = Roo.lib.Event.getXY(e);
34433 this.overlay.hide();
34436 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34437 newSize = this.dragSpecs.startSize +
34438 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34439 endPoint[0] - this.dragSpecs.startPoint[0] :
34440 this.dragSpecs.startPoint[0] - endPoint[0]
34443 newSize = this.dragSpecs.startSize +
34444 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34445 endPoint[1] - this.dragSpecs.startPoint[1] :
34446 this.dragSpecs.startPoint[1] - endPoint[1]
34449 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34450 if(newSize != this.dragSpecs.startSize){
34451 if(this.fireEvent('beforeapply', this, newSize) !== false){
34452 this.adapter.setElementSize(this, newSize);
34453 this.fireEvent("moved", this, newSize);
34454 this.fireEvent("resize", this, newSize);
34460 * Get the adapter this SplitBar uses
34461 * @return The adapter object
34463 getAdapter : function(){
34464 return this.adapter;
34468 * Set the adapter this SplitBar uses
34469 * @param {Object} adapter A SplitBar adapter object
34471 setAdapter : function(adapter){
34472 this.adapter = adapter;
34473 this.adapter.init(this);
34477 * Gets the minimum size for the resizing element
34478 * @return {Number} The minimum size
34480 getMinimumSize : function(){
34481 return this.minSize;
34485 * Sets the minimum size for the resizing element
34486 * @param {Number} minSize The minimum size
34488 setMinimumSize : function(minSize){
34489 this.minSize = minSize;
34493 * Gets the maximum size for the resizing element
34494 * @return {Number} The maximum size
34496 getMaximumSize : function(){
34497 return this.maxSize;
34501 * Sets the maximum size for the resizing element
34502 * @param {Number} maxSize The maximum size
34504 setMaximumSize : function(maxSize){
34505 this.maxSize = maxSize;
34509 * Sets the initialize size for the resizing element
34510 * @param {Number} size The initial size
34512 setCurrentSize : function(size){
34513 var oldAnimate = this.animate;
34514 this.animate = false;
34515 this.adapter.setElementSize(this, size);
34516 this.animate = oldAnimate;
34520 * Destroy this splitbar.
34521 * @param {Boolean} removeEl True to remove the element
34523 destroy : function(removeEl){
34525 this.shim.remove();
34528 this.proxy.parentNode.removeChild(this.proxy);
34536 * @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.
34538 Roo.bootstrap.SplitBar.createProxy = function(dir){
34539 var proxy = new Roo.Element(document.createElement("div"));
34540 proxy.unselectable();
34541 var cls = 'roo-splitbar-proxy';
34542 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34543 document.body.appendChild(proxy.dom);
34548 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34549 * Default Adapter. It assumes the splitter and resizing element are not positioned
34550 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34552 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34555 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34556 // do nothing for now
34557 init : function(s){
34561 * Called before drag operations to get the current size of the resizing element.
34562 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34564 getElementSize : function(s){
34565 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34566 return s.resizingEl.getWidth();
34568 return s.resizingEl.getHeight();
34573 * Called after drag operations to set the size of the resizing element.
34574 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34575 * @param {Number} newSize The new size to set
34576 * @param {Function} onComplete A function to be invoked when resizing is complete
34578 setElementSize : function(s, newSize, onComplete){
34579 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34581 s.resizingEl.setWidth(newSize);
34583 onComplete(s, newSize);
34586 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34591 s.resizingEl.setHeight(newSize);
34593 onComplete(s, newSize);
34596 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34603 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34604 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34605 * Adapter that moves the splitter element to align with the resized sizing element.
34606 * Used with an absolute positioned SplitBar.
34607 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34608 * document.body, make sure you assign an id to the body element.
34610 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34611 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34612 this.container = Roo.get(container);
34615 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34616 init : function(s){
34617 this.basic.init(s);
34620 getElementSize : function(s){
34621 return this.basic.getElementSize(s);
34624 setElementSize : function(s, newSize, onComplete){
34625 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34628 moveSplitter : function(s){
34629 var yes = Roo.bootstrap.SplitBar;
34630 switch(s.placement){
34632 s.el.setX(s.resizingEl.getRight());
34635 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34638 s.el.setY(s.resizingEl.getBottom());
34641 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34648 * Orientation constant - Create a vertical SplitBar
34652 Roo.bootstrap.SplitBar.VERTICAL = 1;
34655 * Orientation constant - Create a horizontal SplitBar
34659 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34662 * Placement constant - The resizing element is to the left of the splitter element
34666 Roo.bootstrap.SplitBar.LEFT = 1;
34669 * Placement constant - The resizing element is to the right of the splitter element
34673 Roo.bootstrap.SplitBar.RIGHT = 2;
34676 * Placement constant - The resizing element is positioned above the splitter element
34680 Roo.bootstrap.SplitBar.TOP = 3;
34683 * Placement constant - The resizing element is positioned under splitter element
34687 Roo.bootstrap.SplitBar.BOTTOM = 4;
34688 Roo.namespace("Roo.bootstrap.layout");/*
34690 * Ext JS Library 1.1.1
34691 * Copyright(c) 2006-2007, Ext JS, LLC.
34693 * Originally Released Under LGPL - original licence link has changed is not relivant.
34696 * <script type="text/javascript">
34700 * @class Roo.bootstrap.layout.Manager
34701 * @extends Roo.bootstrap.Component
34702 * Base class for layout managers.
34704 Roo.bootstrap.layout.Manager = function(config)
34706 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34712 /** false to disable window resize monitoring @type Boolean */
34713 this.monitorWindowResize = true;
34718 * Fires when a layout is performed.
34719 * @param {Roo.LayoutManager} this
34723 * @event regionresized
34724 * Fires when the user resizes a region.
34725 * @param {Roo.LayoutRegion} region The resized region
34726 * @param {Number} newSize The new size (width for east/west, height for north/south)
34728 "regionresized" : true,
34730 * @event regioncollapsed
34731 * Fires when a region is collapsed.
34732 * @param {Roo.LayoutRegion} region The collapsed region
34734 "regioncollapsed" : true,
34736 * @event regionexpanded
34737 * Fires when a region is expanded.
34738 * @param {Roo.LayoutRegion} region The expanded region
34740 "regionexpanded" : true
34742 this.updating = false;
34745 this.el = Roo.get(config.el);
34751 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34756 monitorWindowResize : true,
34762 onRender : function(ct, position)
34765 this.el = Roo.get(ct);
34768 //this.fireEvent('render',this);
34772 initEvents: function()
34776 // ie scrollbar fix
34777 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34778 document.body.scroll = "no";
34779 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34780 this.el.position('relative');
34782 this.id = this.el.id;
34783 this.el.addClass("roo-layout-container");
34784 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34785 if(this.el.dom != document.body ) {
34786 this.el.on('resize', this.layout,this);
34787 this.el.on('show', this.layout,this);
34793 * Returns true if this layout is currently being updated
34794 * @return {Boolean}
34796 isUpdating : function(){
34797 return this.updating;
34801 * Suspend the LayoutManager from doing auto-layouts while
34802 * making multiple add or remove calls
34804 beginUpdate : function(){
34805 this.updating = true;
34809 * Restore auto-layouts and optionally disable the manager from performing a layout
34810 * @param {Boolean} noLayout true to disable a layout update
34812 endUpdate : function(noLayout){
34813 this.updating = false;
34819 layout: function(){
34823 onRegionResized : function(region, newSize){
34824 this.fireEvent("regionresized", region, newSize);
34828 onRegionCollapsed : function(region){
34829 this.fireEvent("regioncollapsed", region);
34832 onRegionExpanded : function(region){
34833 this.fireEvent("regionexpanded", region);
34837 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34838 * performs box-model adjustments.
34839 * @return {Object} The size as an object {width: (the width), height: (the height)}
34841 getViewSize : function()
34844 if(this.el.dom != document.body){
34845 size = this.el.getSize();
34847 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34849 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34850 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34855 * Returns the Element this layout is bound to.
34856 * @return {Roo.Element}
34858 getEl : function(){
34863 * Returns the specified region.
34864 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34865 * @return {Roo.LayoutRegion}
34867 getRegion : function(target){
34868 return this.regions[target.toLowerCase()];
34871 onWindowResize : function(){
34872 if(this.monitorWindowResize){
34879 * Ext JS Library 1.1.1
34880 * Copyright(c) 2006-2007, Ext JS, LLC.
34882 * Originally Released Under LGPL - original licence link has changed is not relivant.
34885 * <script type="text/javascript">
34888 * @class Roo.bootstrap.layout.Border
34889 * @extends Roo.bootstrap.layout.Manager
34890 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34891 * please see: examples/bootstrap/nested.html<br><br>
34893 <b>The container the layout is rendered into can be either the body element or any other element.
34894 If it is not the body element, the container needs to either be an absolute positioned element,
34895 or you will need to add "position:relative" to the css of the container. You will also need to specify
34896 the container size if it is not the body element.</b>
34899 * Create a new Border
34900 * @param {Object} config Configuration options
34902 Roo.bootstrap.layout.Border = function(config){
34903 config = config || {};
34904 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34908 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34909 if(config[region]){
34910 config[region].region = region;
34911 this.addRegion(config[region]);
34917 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34919 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34921 * Creates and adds a new region if it doesn't already exist.
34922 * @param {String} target The target region key (north, south, east, west or center).
34923 * @param {Object} config The regions config object
34924 * @return {BorderLayoutRegion} The new region
34926 addRegion : function(config)
34928 if(!this.regions[config.region]){
34929 var r = this.factory(config);
34930 this.bindRegion(r);
34932 return this.regions[config.region];
34936 bindRegion : function(r){
34937 this.regions[r.config.region] = r;
34939 r.on("visibilitychange", this.layout, this);
34940 r.on("paneladded", this.layout, this);
34941 r.on("panelremoved", this.layout, this);
34942 r.on("invalidated", this.layout, this);
34943 r.on("resized", this.onRegionResized, this);
34944 r.on("collapsed", this.onRegionCollapsed, this);
34945 r.on("expanded", this.onRegionExpanded, this);
34949 * Performs a layout update.
34951 layout : function()
34953 if(this.updating) {
34957 // render all the rebions if they have not been done alreayd?
34958 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34959 if(this.regions[region] && !this.regions[region].bodyEl){
34960 this.regions[region].onRender(this.el)
34964 var size = this.getViewSize();
34965 var w = size.width;
34966 var h = size.height;
34971 //var x = 0, y = 0;
34973 var rs = this.regions;
34974 var north = rs["north"];
34975 var south = rs["south"];
34976 var west = rs["west"];
34977 var east = rs["east"];
34978 var center = rs["center"];
34979 //if(this.hideOnLayout){ // not supported anymore
34980 //c.el.setStyle("display", "none");
34982 if(north && north.isVisible()){
34983 var b = north.getBox();
34984 var m = north.getMargins();
34985 b.width = w - (m.left+m.right);
34988 centerY = b.height + b.y + m.bottom;
34989 centerH -= centerY;
34990 north.updateBox(this.safeBox(b));
34992 if(south && south.isVisible()){
34993 var b = south.getBox();
34994 var m = south.getMargins();
34995 b.width = w - (m.left+m.right);
34997 var totalHeight = (b.height + m.top + m.bottom);
34998 b.y = h - totalHeight + m.top;
34999 centerH -= totalHeight;
35000 south.updateBox(this.safeBox(b));
35002 if(west && west.isVisible()){
35003 var b = west.getBox();
35004 var m = west.getMargins();
35005 b.height = centerH - (m.top+m.bottom);
35007 b.y = centerY + m.top;
35008 var totalWidth = (b.width + m.left + m.right);
35009 centerX += totalWidth;
35010 centerW -= totalWidth;
35011 west.updateBox(this.safeBox(b));
35013 if(east && east.isVisible()){
35014 var b = east.getBox();
35015 var m = east.getMargins();
35016 b.height = centerH - (m.top+m.bottom);
35017 var totalWidth = (b.width + m.left + m.right);
35018 b.x = w - totalWidth + m.left;
35019 b.y = centerY + m.top;
35020 centerW -= totalWidth;
35021 east.updateBox(this.safeBox(b));
35024 var m = center.getMargins();
35026 x: centerX + m.left,
35027 y: centerY + m.top,
35028 width: centerW - (m.left+m.right),
35029 height: centerH - (m.top+m.bottom)
35031 //if(this.hideOnLayout){
35032 //center.el.setStyle("display", "block");
35034 center.updateBox(this.safeBox(centerBox));
35037 this.fireEvent("layout", this);
35041 safeBox : function(box){
35042 box.width = Math.max(0, box.width);
35043 box.height = Math.max(0, box.height);
35048 * Adds a ContentPanel (or subclass) to this layout.
35049 * @param {String} target The target region key (north, south, east, west or center).
35050 * @param {Roo.ContentPanel} panel The panel to add
35051 * @return {Roo.ContentPanel} The added panel
35053 add : function(target, panel){
35055 target = target.toLowerCase();
35056 return this.regions[target].add(panel);
35060 * Remove a ContentPanel (or subclass) to this layout.
35061 * @param {String} target The target region key (north, south, east, west or center).
35062 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35063 * @return {Roo.ContentPanel} The removed panel
35065 remove : function(target, panel){
35066 target = target.toLowerCase();
35067 return this.regions[target].remove(panel);
35071 * Searches all regions for a panel with the specified id
35072 * @param {String} panelId
35073 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35075 findPanel : function(panelId){
35076 var rs = this.regions;
35077 for(var target in rs){
35078 if(typeof rs[target] != "function"){
35079 var p = rs[target].getPanel(panelId);
35089 * Searches all regions for a panel with the specified id and activates (shows) it.
35090 * @param {String/ContentPanel} panelId The panels id or the panel itself
35091 * @return {Roo.ContentPanel} The shown panel or null
35093 showPanel : function(panelId) {
35094 var rs = this.regions;
35095 for(var target in rs){
35096 var r = rs[target];
35097 if(typeof r != "function"){
35098 if(r.hasPanel(panelId)){
35099 return r.showPanel(panelId);
35107 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35108 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35111 restoreState : function(provider){
35113 provider = Roo.state.Manager;
35115 var sm = new Roo.LayoutStateManager();
35116 sm.init(this, provider);
35122 * Adds a xtype elements to the layout.
35126 xtype : 'ContentPanel',
35133 xtype : 'NestedLayoutPanel',
35139 items : [ ... list of content panels or nested layout panels.. ]
35143 * @param {Object} cfg Xtype definition of item to add.
35145 addxtype : function(cfg)
35147 // basically accepts a pannel...
35148 // can accept a layout region..!?!?
35149 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35152 // theory? children can only be panels??
35154 //if (!cfg.xtype.match(/Panel$/)) {
35159 if (typeof(cfg.region) == 'undefined') {
35160 Roo.log("Failed to add Panel, region was not set");
35164 var region = cfg.region;
35170 xitems = cfg.items;
35177 case 'Content': // ContentPanel (el, cfg)
35178 case 'Scroll': // ContentPanel (el, cfg)
35180 cfg.autoCreate = true;
35181 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35183 // var el = this.el.createChild();
35184 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35187 this.add(region, ret);
35191 case 'TreePanel': // our new panel!
35192 cfg.el = this.el.createChild();
35193 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35194 this.add(region, ret);
35199 // create a new Layout (which is a Border Layout...
35201 var clayout = cfg.layout;
35202 clayout.el = this.el.createChild();
35203 clayout.items = clayout.items || [];
35207 // replace this exitems with the clayout ones..
35208 xitems = clayout.items;
35210 // force background off if it's in center...
35211 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35212 cfg.background = false;
35214 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35217 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35218 //console.log('adding nested layout panel ' + cfg.toSource());
35219 this.add(region, ret);
35220 nb = {}; /// find first...
35225 // needs grid and region
35227 //var el = this.getRegion(region).el.createChild();
35229 *var el = this.el.createChild();
35230 // create the grid first...
35231 cfg.grid.container = el;
35232 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35235 if (region == 'center' && this.active ) {
35236 cfg.background = false;
35239 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35241 this.add(region, ret);
35243 if (cfg.background) {
35244 // render grid on panel activation (if panel background)
35245 ret.on('activate', function(gp) {
35246 if (!gp.grid.rendered) {
35247 // gp.grid.render(el);
35251 // cfg.grid.render(el);
35257 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35258 // it was the old xcomponent building that caused this before.
35259 // espeically if border is the top element in the tree.
35269 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35271 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35272 this.add(region, ret);
35276 throw "Can not add '" + cfg.xtype + "' to Border";
35282 this.beginUpdate();
35286 Roo.each(xitems, function(i) {
35287 region = nb && i.region ? i.region : false;
35289 var add = ret.addxtype(i);
35292 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35293 if (!i.background) {
35294 abn[region] = nb[region] ;
35301 // make the last non-background panel active..
35302 //if (nb) { Roo.log(abn); }
35305 for(var r in abn) {
35306 region = this.getRegion(r);
35308 // tried using nb[r], but it does not work..
35310 region.showPanel(abn[r]);
35321 factory : function(cfg)
35324 var validRegions = Roo.bootstrap.layout.Border.regions;
35326 var target = cfg.region;
35329 var r = Roo.bootstrap.layout;
35333 return new r.North(cfg);
35335 return new r.South(cfg);
35337 return new r.East(cfg);
35339 return new r.West(cfg);
35341 return new r.Center(cfg);
35343 throw 'Layout region "'+target+'" not supported.';
35350 * Ext JS Library 1.1.1
35351 * Copyright(c) 2006-2007, Ext JS, LLC.
35353 * Originally Released Under LGPL - original licence link has changed is not relivant.
35356 * <script type="text/javascript">
35360 * @class Roo.bootstrap.layout.Basic
35361 * @extends Roo.util.Observable
35362 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35363 * and does not have a titlebar, tabs or any other features. All it does is size and position
35364 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35365 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35366 * @cfg {string} region the region that it inhabits..
35367 * @cfg {bool} skipConfig skip config?
35371 Roo.bootstrap.layout.Basic = function(config){
35373 this.mgr = config.mgr;
35375 this.position = config.region;
35377 var skipConfig = config.skipConfig;
35381 * @scope Roo.BasicLayoutRegion
35385 * @event beforeremove
35386 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35387 * @param {Roo.LayoutRegion} this
35388 * @param {Roo.ContentPanel} panel The panel
35389 * @param {Object} e The cancel event object
35391 "beforeremove" : true,
35393 * @event invalidated
35394 * Fires when the layout for this region is changed.
35395 * @param {Roo.LayoutRegion} this
35397 "invalidated" : true,
35399 * @event visibilitychange
35400 * Fires when this region is shown or hidden
35401 * @param {Roo.LayoutRegion} this
35402 * @param {Boolean} visibility true or false
35404 "visibilitychange" : true,
35406 * @event paneladded
35407 * Fires when a panel is added.
35408 * @param {Roo.LayoutRegion} this
35409 * @param {Roo.ContentPanel} panel The panel
35411 "paneladded" : true,
35413 * @event panelremoved
35414 * Fires when a panel is removed.
35415 * @param {Roo.LayoutRegion} this
35416 * @param {Roo.ContentPanel} panel The panel
35418 "panelremoved" : true,
35420 * @event beforecollapse
35421 * Fires when this region before collapse.
35422 * @param {Roo.LayoutRegion} this
35424 "beforecollapse" : true,
35427 * Fires when this region is collapsed.
35428 * @param {Roo.LayoutRegion} this
35430 "collapsed" : true,
35433 * Fires when this region is expanded.
35434 * @param {Roo.LayoutRegion} this
35439 * Fires when this region is slid into view.
35440 * @param {Roo.LayoutRegion} this
35442 "slideshow" : true,
35445 * Fires when this region slides out of view.
35446 * @param {Roo.LayoutRegion} this
35448 "slidehide" : true,
35450 * @event panelactivated
35451 * Fires when a panel is activated.
35452 * @param {Roo.LayoutRegion} this
35453 * @param {Roo.ContentPanel} panel The activated panel
35455 "panelactivated" : true,
35458 * Fires when the user resizes this region.
35459 * @param {Roo.LayoutRegion} this
35460 * @param {Number} newSize The new size (width for east/west, height for north/south)
35464 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35465 this.panels = new Roo.util.MixedCollection();
35466 this.panels.getKey = this.getPanelId.createDelegate(this);
35468 this.activePanel = null;
35469 // ensure listeners are added...
35471 if (config.listeners || config.events) {
35472 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35473 listeners : config.listeners || {},
35474 events : config.events || {}
35478 if(skipConfig !== true){
35479 this.applyConfig(config);
35483 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35485 getPanelId : function(p){
35489 applyConfig : function(config){
35490 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35491 this.config = config;
35496 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35497 * the width, for horizontal (north, south) the height.
35498 * @param {Number} newSize The new width or height
35500 resizeTo : function(newSize){
35501 var el = this.el ? this.el :
35502 (this.activePanel ? this.activePanel.getEl() : null);
35504 switch(this.position){
35507 el.setWidth(newSize);
35508 this.fireEvent("resized", this, newSize);
35512 el.setHeight(newSize);
35513 this.fireEvent("resized", this, newSize);
35519 getBox : function(){
35520 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35523 getMargins : function(){
35524 return this.margins;
35527 updateBox : function(box){
35529 var el = this.activePanel.getEl();
35530 el.dom.style.left = box.x + "px";
35531 el.dom.style.top = box.y + "px";
35532 this.activePanel.setSize(box.width, box.height);
35536 * Returns the container element for this region.
35537 * @return {Roo.Element}
35539 getEl : function(){
35540 return this.activePanel;
35544 * Returns true if this region is currently visible.
35545 * @return {Boolean}
35547 isVisible : function(){
35548 return this.activePanel ? true : false;
35551 setActivePanel : function(panel){
35552 panel = this.getPanel(panel);
35553 if(this.activePanel && this.activePanel != panel){
35554 this.activePanel.setActiveState(false);
35555 this.activePanel.getEl().setLeftTop(-10000,-10000);
35557 this.activePanel = panel;
35558 panel.setActiveState(true);
35560 panel.setSize(this.box.width, this.box.height);
35562 this.fireEvent("panelactivated", this, panel);
35563 this.fireEvent("invalidated");
35567 * Show the specified panel.
35568 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35569 * @return {Roo.ContentPanel} The shown panel or null
35571 showPanel : function(panel){
35572 panel = this.getPanel(panel);
35574 this.setActivePanel(panel);
35580 * Get the active panel for this region.
35581 * @return {Roo.ContentPanel} The active panel or null
35583 getActivePanel : function(){
35584 return this.activePanel;
35588 * Add the passed ContentPanel(s)
35589 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35590 * @return {Roo.ContentPanel} The panel added (if only one was added)
35592 add : function(panel){
35593 if(arguments.length > 1){
35594 for(var i = 0, len = arguments.length; i < len; i++) {
35595 this.add(arguments[i]);
35599 if(this.hasPanel(panel)){
35600 this.showPanel(panel);
35603 var el = panel.getEl();
35604 if(el.dom.parentNode != this.mgr.el.dom){
35605 this.mgr.el.dom.appendChild(el.dom);
35607 if(panel.setRegion){
35608 panel.setRegion(this);
35610 this.panels.add(panel);
35611 el.setStyle("position", "absolute");
35612 if(!panel.background){
35613 this.setActivePanel(panel);
35614 if(this.config.initialSize && this.panels.getCount()==1){
35615 this.resizeTo(this.config.initialSize);
35618 this.fireEvent("paneladded", this, panel);
35623 * Returns true if the panel is in this region.
35624 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35625 * @return {Boolean}
35627 hasPanel : function(panel){
35628 if(typeof panel == "object"){ // must be panel obj
35629 panel = panel.getId();
35631 return this.getPanel(panel) ? true : false;
35635 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35636 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35637 * @param {Boolean} preservePanel Overrides the config preservePanel option
35638 * @return {Roo.ContentPanel} The panel that was removed
35640 remove : function(panel, preservePanel){
35641 panel = this.getPanel(panel);
35646 this.fireEvent("beforeremove", this, panel, e);
35647 if(e.cancel === true){
35650 var panelId = panel.getId();
35651 this.panels.removeKey(panelId);
35656 * Returns the panel specified or null if it's not in this region.
35657 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35658 * @return {Roo.ContentPanel}
35660 getPanel : function(id){
35661 if(typeof id == "object"){ // must be panel obj
35664 return this.panels.get(id);
35668 * Returns this regions position (north/south/east/west/center).
35671 getPosition: function(){
35672 return this.position;
35676 * Ext JS Library 1.1.1
35677 * Copyright(c) 2006-2007, Ext JS, LLC.
35679 * Originally Released Under LGPL - original licence link has changed is not relivant.
35682 * <script type="text/javascript">
35686 * @class Roo.bootstrap.layout.Region
35687 * @extends Roo.bootstrap.layout.Basic
35688 * This class represents a region in a layout manager.
35690 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35691 * @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})
35692 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35693 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35694 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35695 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35696 * @cfg {String} title The title for the region (overrides panel titles)
35697 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35698 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35699 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35700 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35701 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35702 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35703 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35704 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35705 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35706 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35708 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35709 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35710 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35711 * @cfg {Number} width For East/West panels
35712 * @cfg {Number} height For North/South panels
35713 * @cfg {Boolean} split To show the splitter
35714 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35716 * @cfg {string} cls Extra CSS classes to add to region
35718 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35719 * @cfg {string} region the region that it inhabits..
35722 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35723 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35725 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35726 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35727 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35729 Roo.bootstrap.layout.Region = function(config)
35731 this.applyConfig(config);
35733 var mgr = config.mgr;
35734 var pos = config.region;
35735 config.skipConfig = true;
35736 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35739 this.onRender(mgr.el);
35742 this.visible = true;
35743 this.collapsed = false;
35744 this.unrendered_panels = [];
35747 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35749 position: '', // set by wrapper (eg. north/south etc..)
35750 unrendered_panels : null, // unrendered panels.
35751 createBody : function(){
35752 /** This region's body element
35753 * @type Roo.Element */
35754 this.bodyEl = this.el.createChild({
35756 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35760 onRender: function(ctr, pos)
35762 var dh = Roo.DomHelper;
35763 /** This region's container element
35764 * @type Roo.Element */
35765 this.el = dh.append(ctr.dom, {
35767 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35769 /** This region's title element
35770 * @type Roo.Element */
35772 this.titleEl = dh.append(this.el.dom,
35775 unselectable: "on",
35776 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35778 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35779 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35782 this.titleEl.enableDisplayMode();
35783 /** This region's title text element
35784 * @type HTMLElement */
35785 this.titleTextEl = this.titleEl.dom.firstChild;
35786 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35788 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35789 this.closeBtn.enableDisplayMode();
35790 this.closeBtn.on("click", this.closeClicked, this);
35791 this.closeBtn.hide();
35793 this.createBody(this.config);
35794 if(this.config.hideWhenEmpty){
35796 this.on("paneladded", this.validateVisibility, this);
35797 this.on("panelremoved", this.validateVisibility, this);
35799 if(this.autoScroll){
35800 this.bodyEl.setStyle("overflow", "auto");
35802 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35804 //if(c.titlebar !== false){
35805 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35806 this.titleEl.hide();
35808 this.titleEl.show();
35809 if(this.config.title){
35810 this.titleTextEl.innerHTML = this.config.title;
35814 if(this.config.collapsed){
35815 this.collapse(true);
35817 if(this.config.hidden){
35821 if (this.unrendered_panels && this.unrendered_panels.length) {
35822 for (var i =0;i< this.unrendered_panels.length; i++) {
35823 this.add(this.unrendered_panels[i]);
35825 this.unrendered_panels = null;
35831 applyConfig : function(c)
35834 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35835 var dh = Roo.DomHelper;
35836 if(c.titlebar !== false){
35837 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35838 this.collapseBtn.on("click", this.collapse, this);
35839 this.collapseBtn.enableDisplayMode();
35841 if(c.showPin === true || this.showPin){
35842 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35843 this.stickBtn.enableDisplayMode();
35844 this.stickBtn.on("click", this.expand, this);
35845 this.stickBtn.hide();
35850 /** This region's collapsed element
35851 * @type Roo.Element */
35854 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35855 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35858 if(c.floatable !== false){
35859 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35860 this.collapsedEl.on("click", this.collapseClick, this);
35863 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35864 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35865 id: "message", unselectable: "on", style:{"float":"left"}});
35866 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35868 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35869 this.expandBtn.on("click", this.expand, this);
35873 if(this.collapseBtn){
35874 this.collapseBtn.setVisible(c.collapsible == true);
35877 this.cmargins = c.cmargins || this.cmargins ||
35878 (this.position == "west" || this.position == "east" ?
35879 {top: 0, left: 2, right:2, bottom: 0} :
35880 {top: 2, left: 0, right:0, bottom: 2});
35882 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35885 this.bottomTabs = c.tabPosition != "top";
35887 this.autoScroll = c.autoScroll || false;
35892 this.duration = c.duration || .30;
35893 this.slideDuration = c.slideDuration || .45;
35898 * Returns true if this region is currently visible.
35899 * @return {Boolean}
35901 isVisible : function(){
35902 return this.visible;
35906 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35907 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35909 //setCollapsedTitle : function(title){
35910 // title = title || " ";
35911 // if(this.collapsedTitleTextEl){
35912 // this.collapsedTitleTextEl.innerHTML = title;
35916 getBox : function(){
35918 // if(!this.collapsed){
35919 b = this.el.getBox(false, true);
35921 // b = this.collapsedEl.getBox(false, true);
35926 getMargins : function(){
35927 return this.margins;
35928 //return this.collapsed ? this.cmargins : this.margins;
35931 highlight : function(){
35932 this.el.addClass("x-layout-panel-dragover");
35935 unhighlight : function(){
35936 this.el.removeClass("x-layout-panel-dragover");
35939 updateBox : function(box)
35941 if (!this.bodyEl) {
35942 return; // not rendered yet..
35946 if(!this.collapsed){
35947 this.el.dom.style.left = box.x + "px";
35948 this.el.dom.style.top = box.y + "px";
35949 this.updateBody(box.width, box.height);
35951 this.collapsedEl.dom.style.left = box.x + "px";
35952 this.collapsedEl.dom.style.top = box.y + "px";
35953 this.collapsedEl.setSize(box.width, box.height);
35956 this.tabs.autoSizeTabs();
35960 updateBody : function(w, h)
35963 this.el.setWidth(w);
35964 w -= this.el.getBorderWidth("rl");
35965 if(this.config.adjustments){
35966 w += this.config.adjustments[0];
35969 if(h !== null && h > 0){
35970 this.el.setHeight(h);
35971 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35972 h -= this.el.getBorderWidth("tb");
35973 if(this.config.adjustments){
35974 h += this.config.adjustments[1];
35976 this.bodyEl.setHeight(h);
35978 h = this.tabs.syncHeight(h);
35981 if(this.panelSize){
35982 w = w !== null ? w : this.panelSize.width;
35983 h = h !== null ? h : this.panelSize.height;
35985 if(this.activePanel){
35986 var el = this.activePanel.getEl();
35987 w = w !== null ? w : el.getWidth();
35988 h = h !== null ? h : el.getHeight();
35989 this.panelSize = {width: w, height: h};
35990 this.activePanel.setSize(w, h);
35992 if(Roo.isIE && this.tabs){
35993 this.tabs.el.repaint();
35998 * Returns the container element for this region.
35999 * @return {Roo.Element}
36001 getEl : function(){
36006 * Hides this region.
36009 //if(!this.collapsed){
36010 this.el.dom.style.left = "-2000px";
36013 // this.collapsedEl.dom.style.left = "-2000px";
36014 // this.collapsedEl.hide();
36016 this.visible = false;
36017 this.fireEvent("visibilitychange", this, false);
36021 * Shows this region if it was previously hidden.
36024 //if(!this.collapsed){
36027 // this.collapsedEl.show();
36029 this.visible = true;
36030 this.fireEvent("visibilitychange", this, true);
36033 closeClicked : function(){
36034 if(this.activePanel){
36035 this.remove(this.activePanel);
36039 collapseClick : function(e){
36041 e.stopPropagation();
36044 e.stopPropagation();
36050 * Collapses this region.
36051 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36054 collapse : function(skipAnim, skipCheck = false){
36055 if(this.collapsed) {
36059 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36061 this.collapsed = true;
36063 this.split.el.hide();
36065 if(this.config.animate && skipAnim !== true){
36066 this.fireEvent("invalidated", this);
36067 this.animateCollapse();
36069 this.el.setLocation(-20000,-20000);
36071 this.collapsedEl.show();
36072 this.fireEvent("collapsed", this);
36073 this.fireEvent("invalidated", this);
36079 animateCollapse : function(){
36084 * Expands this region if it was previously collapsed.
36085 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36086 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36089 expand : function(e, skipAnim){
36091 e.stopPropagation();
36093 if(!this.collapsed || this.el.hasActiveFx()) {
36097 this.afterSlideIn();
36100 this.collapsed = false;
36101 if(this.config.animate && skipAnim !== true){
36102 this.animateExpand();
36106 this.split.el.show();
36108 this.collapsedEl.setLocation(-2000,-2000);
36109 this.collapsedEl.hide();
36110 this.fireEvent("invalidated", this);
36111 this.fireEvent("expanded", this);
36115 animateExpand : function(){
36119 initTabs : function()
36121 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36123 var ts = new Roo.bootstrap.panel.Tabs({
36124 el: this.bodyEl.dom,
36125 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36126 disableTooltips: this.config.disableTabTips,
36127 toolbar : this.config.toolbar
36130 if(this.config.hideTabs){
36131 ts.stripWrap.setDisplayed(false);
36134 ts.resizeTabs = this.config.resizeTabs === true;
36135 ts.minTabWidth = this.config.minTabWidth || 40;
36136 ts.maxTabWidth = this.config.maxTabWidth || 250;
36137 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36138 ts.monitorResize = false;
36139 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36140 ts.bodyEl.addClass('roo-layout-tabs-body');
36141 this.panels.each(this.initPanelAsTab, this);
36144 initPanelAsTab : function(panel){
36145 var ti = this.tabs.addTab(
36149 this.config.closeOnTab && panel.isClosable(),
36152 if(panel.tabTip !== undefined){
36153 ti.setTooltip(panel.tabTip);
36155 ti.on("activate", function(){
36156 this.setActivePanel(panel);
36159 if(this.config.closeOnTab){
36160 ti.on("beforeclose", function(t, e){
36162 this.remove(panel);
36166 panel.tabItem = ti;
36171 updatePanelTitle : function(panel, title)
36173 if(this.activePanel == panel){
36174 this.updateTitle(title);
36177 var ti = this.tabs.getTab(panel.getEl().id);
36179 if(panel.tabTip !== undefined){
36180 ti.setTooltip(panel.tabTip);
36185 updateTitle : function(title){
36186 if(this.titleTextEl && !this.config.title){
36187 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36191 setActivePanel : function(panel)
36193 panel = this.getPanel(panel);
36194 if(this.activePanel && this.activePanel != panel){
36195 if(this.activePanel.setActiveState(false) === false){
36199 this.activePanel = panel;
36200 panel.setActiveState(true);
36201 if(this.panelSize){
36202 panel.setSize(this.panelSize.width, this.panelSize.height);
36205 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36207 this.updateTitle(panel.getTitle());
36209 this.fireEvent("invalidated", this);
36211 this.fireEvent("panelactivated", this, panel);
36215 * Shows the specified panel.
36216 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36217 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36219 showPanel : function(panel)
36221 panel = this.getPanel(panel);
36224 var tab = this.tabs.getTab(panel.getEl().id);
36225 if(tab.isHidden()){
36226 this.tabs.unhideTab(tab.id);
36230 this.setActivePanel(panel);
36237 * Get the active panel for this region.
36238 * @return {Roo.ContentPanel} The active panel or null
36240 getActivePanel : function(){
36241 return this.activePanel;
36244 validateVisibility : function(){
36245 if(this.panels.getCount() < 1){
36246 this.updateTitle(" ");
36247 this.closeBtn.hide();
36250 if(!this.isVisible()){
36257 * Adds the passed ContentPanel(s) to this region.
36258 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36259 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36261 add : function(panel)
36263 if(arguments.length > 1){
36264 for(var i = 0, len = arguments.length; i < len; i++) {
36265 this.add(arguments[i]);
36270 // if we have not been rendered yet, then we can not really do much of this..
36271 if (!this.bodyEl) {
36272 this.unrendered_panels.push(panel);
36279 if(this.hasPanel(panel)){
36280 this.showPanel(panel);
36283 panel.setRegion(this);
36284 this.panels.add(panel);
36285 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36286 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36287 // and hide them... ???
36288 this.bodyEl.dom.appendChild(panel.getEl().dom);
36289 if(panel.background !== true){
36290 this.setActivePanel(panel);
36292 this.fireEvent("paneladded", this, panel);
36299 this.initPanelAsTab(panel);
36303 if(panel.background !== true){
36304 this.tabs.activate(panel.getEl().id);
36306 this.fireEvent("paneladded", this, panel);
36311 * Hides the tab for the specified panel.
36312 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36314 hidePanel : function(panel){
36315 if(this.tabs && (panel = this.getPanel(panel))){
36316 this.tabs.hideTab(panel.getEl().id);
36321 * Unhides the tab for a previously hidden panel.
36322 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36324 unhidePanel : function(panel){
36325 if(this.tabs && (panel = this.getPanel(panel))){
36326 this.tabs.unhideTab(panel.getEl().id);
36330 clearPanels : function(){
36331 while(this.panels.getCount() > 0){
36332 this.remove(this.panels.first());
36337 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36338 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36339 * @param {Boolean} preservePanel Overrides the config preservePanel option
36340 * @return {Roo.ContentPanel} The panel that was removed
36342 remove : function(panel, preservePanel)
36344 panel = this.getPanel(panel);
36349 this.fireEvent("beforeremove", this, panel, e);
36350 if(e.cancel === true){
36353 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36354 var panelId = panel.getId();
36355 this.panels.removeKey(panelId);
36357 document.body.appendChild(panel.getEl().dom);
36360 this.tabs.removeTab(panel.getEl().id);
36361 }else if (!preservePanel){
36362 this.bodyEl.dom.removeChild(panel.getEl().dom);
36364 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36365 var p = this.panels.first();
36366 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36367 tempEl.appendChild(p.getEl().dom);
36368 this.bodyEl.update("");
36369 this.bodyEl.dom.appendChild(p.getEl().dom);
36371 this.updateTitle(p.getTitle());
36373 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36374 this.setActivePanel(p);
36376 panel.setRegion(null);
36377 if(this.activePanel == panel){
36378 this.activePanel = null;
36380 if(this.config.autoDestroy !== false && preservePanel !== true){
36381 try{panel.destroy();}catch(e){}
36383 this.fireEvent("panelremoved", this, panel);
36388 * Returns the TabPanel component used by this region
36389 * @return {Roo.TabPanel}
36391 getTabs : function(){
36395 createTool : function(parentEl, className){
36396 var btn = Roo.DomHelper.append(parentEl, {
36398 cls: "x-layout-tools-button",
36401 cls: "roo-layout-tools-button-inner " + className,
36405 btn.addClassOnOver("roo-layout-tools-button-over");
36410 * Ext JS Library 1.1.1
36411 * Copyright(c) 2006-2007, Ext JS, LLC.
36413 * Originally Released Under LGPL - original licence link has changed is not relivant.
36416 * <script type="text/javascript">
36422 * @class Roo.SplitLayoutRegion
36423 * @extends Roo.LayoutRegion
36424 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36426 Roo.bootstrap.layout.Split = function(config){
36427 this.cursor = config.cursor;
36428 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36431 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36433 splitTip : "Drag to resize.",
36434 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36435 useSplitTips : false,
36437 applyConfig : function(config){
36438 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36441 onRender : function(ctr,pos) {
36443 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36444 if(!this.config.split){
36449 var splitEl = Roo.DomHelper.append(ctr.dom, {
36451 id: this.el.id + "-split",
36452 cls: "roo-layout-split roo-layout-split-"+this.position,
36455 /** The SplitBar for this region
36456 * @type Roo.SplitBar */
36457 // does not exist yet...
36458 Roo.log([this.position, this.orientation]);
36460 this.split = new Roo.bootstrap.SplitBar({
36461 dragElement : splitEl,
36462 resizingElement: this.el,
36463 orientation : this.orientation
36466 this.split.on("moved", this.onSplitMove, this);
36467 this.split.useShim = this.config.useShim === true;
36468 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36469 if(this.useSplitTips){
36470 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36472 //if(config.collapsible){
36473 // this.split.el.on("dblclick", this.collapse, this);
36476 if(typeof this.config.minSize != "undefined"){
36477 this.split.minSize = this.config.minSize;
36479 if(typeof this.config.maxSize != "undefined"){
36480 this.split.maxSize = this.config.maxSize;
36482 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36483 this.hideSplitter();
36488 getHMaxSize : function(){
36489 var cmax = this.config.maxSize || 10000;
36490 var center = this.mgr.getRegion("center");
36491 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36494 getVMaxSize : function(){
36495 var cmax = this.config.maxSize || 10000;
36496 var center = this.mgr.getRegion("center");
36497 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36500 onSplitMove : function(split, newSize){
36501 this.fireEvent("resized", this, newSize);
36505 * Returns the {@link Roo.SplitBar} for this region.
36506 * @return {Roo.SplitBar}
36508 getSplitBar : function(){
36513 this.hideSplitter();
36514 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36517 hideSplitter : function(){
36519 this.split.el.setLocation(-2000,-2000);
36520 this.split.el.hide();
36526 this.split.el.show();
36528 Roo.bootstrap.layout.Split.superclass.show.call(this);
36531 beforeSlide: function(){
36532 if(Roo.isGecko){// firefox overflow auto bug workaround
36533 this.bodyEl.clip();
36535 this.tabs.bodyEl.clip();
36537 if(this.activePanel){
36538 this.activePanel.getEl().clip();
36540 if(this.activePanel.beforeSlide){
36541 this.activePanel.beforeSlide();
36547 afterSlide : function(){
36548 if(Roo.isGecko){// firefox overflow auto bug workaround
36549 this.bodyEl.unclip();
36551 this.tabs.bodyEl.unclip();
36553 if(this.activePanel){
36554 this.activePanel.getEl().unclip();
36555 if(this.activePanel.afterSlide){
36556 this.activePanel.afterSlide();
36562 initAutoHide : function(){
36563 if(this.autoHide !== false){
36564 if(!this.autoHideHd){
36565 var st = new Roo.util.DelayedTask(this.slideIn, this);
36566 this.autoHideHd = {
36567 "mouseout": function(e){
36568 if(!e.within(this.el, true)){
36572 "mouseover" : function(e){
36578 this.el.on(this.autoHideHd);
36582 clearAutoHide : function(){
36583 if(this.autoHide !== false){
36584 this.el.un("mouseout", this.autoHideHd.mouseout);
36585 this.el.un("mouseover", this.autoHideHd.mouseover);
36589 clearMonitor : function(){
36590 Roo.get(document).un("click", this.slideInIf, this);
36593 // these names are backwards but not changed for compat
36594 slideOut : function(){
36595 if(this.isSlid || this.el.hasActiveFx()){
36598 this.isSlid = true;
36599 if(this.collapseBtn){
36600 this.collapseBtn.hide();
36602 this.closeBtnState = this.closeBtn.getStyle('display');
36603 this.closeBtn.hide();
36605 this.stickBtn.show();
36608 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36609 this.beforeSlide();
36610 this.el.setStyle("z-index", 10001);
36611 this.el.slideIn(this.getSlideAnchor(), {
36612 callback: function(){
36614 this.initAutoHide();
36615 Roo.get(document).on("click", this.slideInIf, this);
36616 this.fireEvent("slideshow", this);
36623 afterSlideIn : function(){
36624 this.clearAutoHide();
36625 this.isSlid = false;
36626 this.clearMonitor();
36627 this.el.setStyle("z-index", "");
36628 if(this.collapseBtn){
36629 this.collapseBtn.show();
36631 this.closeBtn.setStyle('display', this.closeBtnState);
36633 this.stickBtn.hide();
36635 this.fireEvent("slidehide", this);
36638 slideIn : function(cb){
36639 if(!this.isSlid || this.el.hasActiveFx()){
36643 this.isSlid = false;
36644 this.beforeSlide();
36645 this.el.slideOut(this.getSlideAnchor(), {
36646 callback: function(){
36647 this.el.setLeftTop(-10000, -10000);
36649 this.afterSlideIn();
36657 slideInIf : function(e){
36658 if(!e.within(this.el)){
36663 animateCollapse : function(){
36664 this.beforeSlide();
36665 this.el.setStyle("z-index", 20000);
36666 var anchor = this.getSlideAnchor();
36667 this.el.slideOut(anchor, {
36668 callback : function(){
36669 this.el.setStyle("z-index", "");
36670 this.collapsedEl.slideIn(anchor, {duration:.3});
36672 this.el.setLocation(-10000,-10000);
36674 this.fireEvent("collapsed", this);
36681 animateExpand : function(){
36682 this.beforeSlide();
36683 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36684 this.el.setStyle("z-index", 20000);
36685 this.collapsedEl.hide({
36688 this.el.slideIn(this.getSlideAnchor(), {
36689 callback : function(){
36690 this.el.setStyle("z-index", "");
36693 this.split.el.show();
36695 this.fireEvent("invalidated", this);
36696 this.fireEvent("expanded", this);
36724 getAnchor : function(){
36725 return this.anchors[this.position];
36728 getCollapseAnchor : function(){
36729 return this.canchors[this.position];
36732 getSlideAnchor : function(){
36733 return this.sanchors[this.position];
36736 getAlignAdj : function(){
36737 var cm = this.cmargins;
36738 switch(this.position){
36754 getExpandAdj : function(){
36755 var c = this.collapsedEl, cm = this.cmargins;
36756 switch(this.position){
36758 return [-(cm.right+c.getWidth()+cm.left), 0];
36761 return [cm.right+c.getWidth()+cm.left, 0];
36764 return [0, -(cm.top+cm.bottom+c.getHeight())];
36767 return [0, cm.top+cm.bottom+c.getHeight()];
36773 * Ext JS Library 1.1.1
36774 * Copyright(c) 2006-2007, Ext JS, LLC.
36776 * Originally Released Under LGPL - original licence link has changed is not relivant.
36779 * <script type="text/javascript">
36782 * These classes are private internal classes
36784 Roo.bootstrap.layout.Center = function(config){
36785 config.region = "center";
36786 Roo.bootstrap.layout.Region.call(this, config);
36787 this.visible = true;
36788 this.minWidth = config.minWidth || 20;
36789 this.minHeight = config.minHeight || 20;
36792 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36794 // center panel can't be hidden
36798 // center panel can't be hidden
36801 getMinWidth: function(){
36802 return this.minWidth;
36805 getMinHeight: function(){
36806 return this.minHeight;
36819 Roo.bootstrap.layout.North = function(config)
36821 config.region = 'north';
36822 config.cursor = 'n-resize';
36824 Roo.bootstrap.layout.Split.call(this, config);
36828 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36829 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36830 this.split.el.addClass("roo-layout-split-v");
36832 var size = config.initialSize || config.height;
36833 if(typeof size != "undefined"){
36834 this.el.setHeight(size);
36837 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36839 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36843 getBox : function(){
36844 if(this.collapsed){
36845 return this.collapsedEl.getBox();
36847 var box = this.el.getBox();
36849 box.height += this.split.el.getHeight();
36854 updateBox : function(box){
36855 if(this.split && !this.collapsed){
36856 box.height -= this.split.el.getHeight();
36857 this.split.el.setLeft(box.x);
36858 this.split.el.setTop(box.y+box.height);
36859 this.split.el.setWidth(box.width);
36861 if(this.collapsed){
36862 this.updateBody(box.width, null);
36864 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36872 Roo.bootstrap.layout.South = function(config){
36873 config.region = 'south';
36874 config.cursor = 's-resize';
36875 Roo.bootstrap.layout.Split.call(this, config);
36877 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36878 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36879 this.split.el.addClass("roo-layout-split-v");
36881 var size = config.initialSize || config.height;
36882 if(typeof size != "undefined"){
36883 this.el.setHeight(size);
36887 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36888 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36889 getBox : function(){
36890 if(this.collapsed){
36891 return this.collapsedEl.getBox();
36893 var box = this.el.getBox();
36895 var sh = this.split.el.getHeight();
36902 updateBox : function(box){
36903 if(this.split && !this.collapsed){
36904 var sh = this.split.el.getHeight();
36907 this.split.el.setLeft(box.x);
36908 this.split.el.setTop(box.y-sh);
36909 this.split.el.setWidth(box.width);
36911 if(this.collapsed){
36912 this.updateBody(box.width, null);
36914 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36918 Roo.bootstrap.layout.East = function(config){
36919 config.region = "east";
36920 config.cursor = "e-resize";
36921 Roo.bootstrap.layout.Split.call(this, config);
36923 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36924 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36925 this.split.el.addClass("roo-layout-split-h");
36927 var size = config.initialSize || config.width;
36928 if(typeof size != "undefined"){
36929 this.el.setWidth(size);
36932 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36933 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36934 getBox : function(){
36935 if(this.collapsed){
36936 return this.collapsedEl.getBox();
36938 var box = this.el.getBox();
36940 var sw = this.split.el.getWidth();
36947 updateBox : function(box){
36948 if(this.split && !this.collapsed){
36949 var sw = this.split.el.getWidth();
36951 this.split.el.setLeft(box.x);
36952 this.split.el.setTop(box.y);
36953 this.split.el.setHeight(box.height);
36956 if(this.collapsed){
36957 this.updateBody(null, box.height);
36959 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36963 Roo.bootstrap.layout.West = function(config){
36964 config.region = "west";
36965 config.cursor = "w-resize";
36967 Roo.bootstrap.layout.Split.call(this, config);
36969 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36970 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36971 this.split.el.addClass("roo-layout-split-h");
36975 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36976 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36978 onRender: function(ctr, pos)
36980 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36981 var size = this.config.initialSize || this.config.width;
36982 if(typeof size != "undefined"){
36983 this.el.setWidth(size);
36987 getBox : function(){
36988 if(this.collapsed){
36989 return this.collapsedEl.getBox();
36991 var box = this.el.getBox();
36993 box.width += this.split.el.getWidth();
36998 updateBox : function(box){
36999 if(this.split && !this.collapsed){
37000 var sw = this.split.el.getWidth();
37002 this.split.el.setLeft(box.x+box.width);
37003 this.split.el.setTop(box.y);
37004 this.split.el.setHeight(box.height);
37006 if(this.collapsed){
37007 this.updateBody(null, box.height);
37009 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37012 Roo.namespace("Roo.bootstrap.panel");/*
37014 * Ext JS Library 1.1.1
37015 * Copyright(c) 2006-2007, Ext JS, LLC.
37017 * Originally Released Under LGPL - original licence link has changed is not relivant.
37020 * <script type="text/javascript">
37023 * @class Roo.ContentPanel
37024 * @extends Roo.util.Observable
37025 * A basic ContentPanel element.
37026 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37027 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37028 * @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
37029 * @cfg {Boolean} closable True if the panel can be closed/removed
37030 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37031 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37032 * @cfg {Toolbar} toolbar A toolbar for this panel
37033 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37034 * @cfg {String} title The title for this panel
37035 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37036 * @cfg {String} url Calls {@link #setUrl} with this value
37037 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37038 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37039 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37040 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37041 * @cfg {Boolean} badges render the badges
37044 * Create a new ContentPanel.
37045 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37046 * @param {String/Object} config A string to set only the title or a config object
37047 * @param {String} content (optional) Set the HTML content for this panel
37048 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37050 Roo.bootstrap.panel.Content = function( config){
37052 this.tpl = config.tpl || false;
37054 var el = config.el;
37055 var content = config.content;
37057 if(config.autoCreate){ // xtype is available if this is called from factory
37060 this.el = Roo.get(el);
37061 if(!this.el && config && config.autoCreate){
37062 if(typeof config.autoCreate == "object"){
37063 if(!config.autoCreate.id){
37064 config.autoCreate.id = config.id||el;
37066 this.el = Roo.DomHelper.append(document.body,
37067 config.autoCreate, true);
37069 var elcfg = { tag: "div",
37070 cls: "roo-layout-inactive-content",
37074 elcfg.html = config.html;
37078 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37081 this.closable = false;
37082 this.loaded = false;
37083 this.active = false;
37086 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37088 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37090 this.wrapEl = this.el; //this.el.wrap();
37092 if (config.toolbar.items) {
37093 ti = config.toolbar.items ;
37094 delete config.toolbar.items ;
37098 this.toolbar.render(this.wrapEl, 'before');
37099 for(var i =0;i < ti.length;i++) {
37100 // Roo.log(['add child', items[i]]);
37101 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37103 this.toolbar.items = nitems;
37104 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37105 delete config.toolbar;
37109 // xtype created footer. - not sure if will work as we normally have to render first..
37110 if (this.footer && !this.footer.el && this.footer.xtype) {
37111 if (!this.wrapEl) {
37112 this.wrapEl = this.el.wrap();
37115 this.footer.container = this.wrapEl.createChild();
37117 this.footer = Roo.factory(this.footer, Roo);
37122 if(typeof config == "string"){
37123 this.title = config;
37125 Roo.apply(this, config);
37129 this.resizeEl = Roo.get(this.resizeEl, true);
37131 this.resizeEl = this.el;
37133 // handle view.xtype
37141 * Fires when this panel is activated.
37142 * @param {Roo.ContentPanel} this
37146 * @event deactivate
37147 * Fires when this panel is activated.
37148 * @param {Roo.ContentPanel} this
37150 "deactivate" : true,
37154 * Fires when this panel is resized if fitToFrame is true.
37155 * @param {Roo.ContentPanel} this
37156 * @param {Number} width The width after any component adjustments
37157 * @param {Number} height The height after any component adjustments
37163 * Fires when this tab is created
37164 * @param {Roo.ContentPanel} this
37175 if(this.autoScroll){
37176 this.resizeEl.setStyle("overflow", "auto");
37178 // fix randome scrolling
37179 //this.el.on('scroll', function() {
37180 // Roo.log('fix random scolling');
37181 // this.scrollTo('top',0);
37184 content = content || this.content;
37186 this.setContent(content);
37188 if(config && config.url){
37189 this.setUrl(this.url, this.params, this.loadOnce);
37194 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37196 if (this.view && typeof(this.view.xtype) != 'undefined') {
37197 this.view.el = this.el.appendChild(document.createElement("div"));
37198 this.view = Roo.factory(this.view);
37199 this.view.render && this.view.render(false, '');
37203 this.fireEvent('render', this);
37206 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37210 setRegion : function(region){
37211 this.region = region;
37212 this.setActiveClass(region && !this.background);
37216 setActiveClass: function(state)
37219 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37220 this.el.setStyle('position','relative');
37222 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37223 this.el.setStyle('position', 'absolute');
37228 * Returns the toolbar for this Panel if one was configured.
37229 * @return {Roo.Toolbar}
37231 getToolbar : function(){
37232 return this.toolbar;
37235 setActiveState : function(active)
37237 this.active = active;
37238 this.setActiveClass(active);
37240 if(this.fireEvent("deactivate", this) === false){
37245 this.fireEvent("activate", this);
37249 * Updates this panel's element
37250 * @param {String} content The new content
37251 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37253 setContent : function(content, loadScripts){
37254 this.el.update(content, loadScripts);
37257 ignoreResize : function(w, h){
37258 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37261 this.lastSize = {width: w, height: h};
37266 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37267 * @return {Roo.UpdateManager} The UpdateManager
37269 getUpdateManager : function(){
37270 return this.el.getUpdateManager();
37273 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37274 * @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:
37277 url: "your-url.php",
37278 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37279 callback: yourFunction,
37280 scope: yourObject, //(optional scope)
37283 text: "Loading...",
37288 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37289 * 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.
37290 * @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}
37291 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37292 * @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.
37293 * @return {Roo.ContentPanel} this
37296 var um = this.el.getUpdateManager();
37297 um.update.apply(um, arguments);
37303 * 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.
37304 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37305 * @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)
37306 * @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)
37307 * @return {Roo.UpdateManager} The UpdateManager
37309 setUrl : function(url, params, loadOnce){
37310 if(this.refreshDelegate){
37311 this.removeListener("activate", this.refreshDelegate);
37313 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37314 this.on("activate", this.refreshDelegate);
37315 return this.el.getUpdateManager();
37318 _handleRefresh : function(url, params, loadOnce){
37319 if(!loadOnce || !this.loaded){
37320 var updater = this.el.getUpdateManager();
37321 updater.update(url, params, this._setLoaded.createDelegate(this));
37325 _setLoaded : function(){
37326 this.loaded = true;
37330 * Returns this panel's id
37333 getId : function(){
37338 * Returns this panel's element - used by regiosn to add.
37339 * @return {Roo.Element}
37341 getEl : function(){
37342 return this.wrapEl || this.el;
37347 adjustForComponents : function(width, height)
37349 //Roo.log('adjustForComponents ');
37350 if(this.resizeEl != this.el){
37351 width -= this.el.getFrameWidth('lr');
37352 height -= this.el.getFrameWidth('tb');
37355 var te = this.toolbar.getEl();
37356 te.setWidth(width);
37357 height -= te.getHeight();
37360 var te = this.footer.getEl();
37361 te.setWidth(width);
37362 height -= te.getHeight();
37366 if(this.adjustments){
37367 width += this.adjustments[0];
37368 height += this.adjustments[1];
37370 return {"width": width, "height": height};
37373 setSize : function(width, height){
37374 if(this.fitToFrame && !this.ignoreResize(width, height)){
37375 if(this.fitContainer && this.resizeEl != this.el){
37376 this.el.setSize(width, height);
37378 var size = this.adjustForComponents(width, height);
37379 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37380 this.fireEvent('resize', this, size.width, size.height);
37385 * Returns this panel's title
37388 getTitle : function(){
37390 if (typeof(this.title) != 'object') {
37395 for (var k in this.title) {
37396 if (!this.title.hasOwnProperty(k)) {
37400 if (k.indexOf('-') >= 0) {
37401 var s = k.split('-');
37402 for (var i = 0; i<s.length; i++) {
37403 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37406 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37413 * Set this panel's title
37414 * @param {String} title
37416 setTitle : function(title){
37417 this.title = title;
37419 this.region.updatePanelTitle(this, title);
37424 * Returns true is this panel was configured to be closable
37425 * @return {Boolean}
37427 isClosable : function(){
37428 return this.closable;
37431 beforeSlide : function(){
37433 this.resizeEl.clip();
37436 afterSlide : function(){
37438 this.resizeEl.unclip();
37442 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37443 * Will fail silently if the {@link #setUrl} method has not been called.
37444 * This does not activate the panel, just updates its content.
37446 refresh : function(){
37447 if(this.refreshDelegate){
37448 this.loaded = false;
37449 this.refreshDelegate();
37454 * Destroys this panel
37456 destroy : function(){
37457 this.el.removeAllListeners();
37458 var tempEl = document.createElement("span");
37459 tempEl.appendChild(this.el.dom);
37460 tempEl.innerHTML = "";
37466 * form - if the content panel contains a form - this is a reference to it.
37467 * @type {Roo.form.Form}
37471 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37472 * This contains a reference to it.
37478 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37488 * @param {Object} cfg Xtype definition of item to add.
37492 getChildContainer: function () {
37493 return this.getEl();
37498 var ret = new Roo.factory(cfg);
37503 if (cfg.xtype.match(/^Form$/)) {
37506 //if (this.footer) {
37507 // el = this.footer.container.insertSibling(false, 'before');
37509 el = this.el.createChild();
37512 this.form = new Roo.form.Form(cfg);
37515 if ( this.form.allItems.length) {
37516 this.form.render(el.dom);
37520 // should only have one of theses..
37521 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37522 // views.. should not be just added - used named prop 'view''
37524 cfg.el = this.el.appendChild(document.createElement("div"));
37527 var ret = new Roo.factory(cfg);
37529 ret.render && ret.render(false, ''); // render blank..
37539 * @class Roo.bootstrap.panel.Grid
37540 * @extends Roo.bootstrap.panel.Content
37542 * Create a new GridPanel.
37543 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37544 * @param {Object} config A the config object
37550 Roo.bootstrap.panel.Grid = function(config)
37554 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37555 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37557 config.el = this.wrapper;
37558 //this.el = this.wrapper;
37560 if (config.container) {
37561 // ctor'ed from a Border/panel.grid
37564 this.wrapper.setStyle("overflow", "hidden");
37565 this.wrapper.addClass('roo-grid-container');
37570 if(config.toolbar){
37571 var tool_el = this.wrapper.createChild();
37572 this.toolbar = Roo.factory(config.toolbar);
37574 if (config.toolbar.items) {
37575 ti = config.toolbar.items ;
37576 delete config.toolbar.items ;
37580 this.toolbar.render(tool_el);
37581 for(var i =0;i < ti.length;i++) {
37582 // Roo.log(['add child', items[i]]);
37583 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37585 this.toolbar.items = nitems;
37587 delete config.toolbar;
37590 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37591 config.grid.scrollBody = true;;
37592 config.grid.monitorWindowResize = false; // turn off autosizing
37593 config.grid.autoHeight = false;
37594 config.grid.autoWidth = false;
37596 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37598 if (config.background) {
37599 // render grid on panel activation (if panel background)
37600 this.on('activate', function(gp) {
37601 if (!gp.grid.rendered) {
37602 gp.grid.render(this.wrapper);
37603 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37608 this.grid.render(this.wrapper);
37609 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37612 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37613 // ??? needed ??? config.el = this.wrapper;
37618 // xtype created footer. - not sure if will work as we normally have to render first..
37619 if (this.footer && !this.footer.el && this.footer.xtype) {
37621 var ctr = this.grid.getView().getFooterPanel(true);
37622 this.footer.dataSource = this.grid.dataSource;
37623 this.footer = Roo.factory(this.footer, Roo);
37624 this.footer.render(ctr);
37634 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37635 getId : function(){
37636 return this.grid.id;
37640 * Returns the grid for this panel
37641 * @return {Roo.bootstrap.Table}
37643 getGrid : function(){
37647 setSize : function(width, height){
37648 if(!this.ignoreResize(width, height)){
37649 var grid = this.grid;
37650 var size = this.adjustForComponents(width, height);
37651 var gridel = grid.getGridEl();
37652 gridel.setSize(size.width, size.height);
37654 var thd = grid.getGridEl().select('thead',true).first();
37655 var tbd = grid.getGridEl().select('tbody', true).first();
37657 tbd.setSize(width, height - thd.getHeight());
37666 beforeSlide : function(){
37667 this.grid.getView().scroller.clip();
37670 afterSlide : function(){
37671 this.grid.getView().scroller.unclip();
37674 destroy : function(){
37675 this.grid.destroy();
37677 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37682 * @class Roo.bootstrap.panel.Nest
37683 * @extends Roo.bootstrap.panel.Content
37685 * Create a new Panel, that can contain a layout.Border.
37688 * @param {Roo.BorderLayout} layout The layout for this panel
37689 * @param {String/Object} config A string to set only the title or a config object
37691 Roo.bootstrap.panel.Nest = function(config)
37693 // construct with only one argument..
37694 /* FIXME - implement nicer consturctors
37695 if (layout.layout) {
37697 layout = config.layout;
37698 delete config.layout;
37700 if (layout.xtype && !layout.getEl) {
37701 // then layout needs constructing..
37702 layout = Roo.factory(layout, Roo);
37706 config.el = config.layout.getEl();
37708 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37710 config.layout.monitorWindowResize = false; // turn off autosizing
37711 this.layout = config.layout;
37712 this.layout.getEl().addClass("roo-layout-nested-layout");
37719 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37721 setSize : function(width, height){
37722 if(!this.ignoreResize(width, height)){
37723 var size = this.adjustForComponents(width, height);
37724 var el = this.layout.getEl();
37725 if (size.height < 1) {
37726 el.setWidth(size.width);
37728 el.setSize(size.width, size.height);
37730 var touch = el.dom.offsetWidth;
37731 this.layout.layout();
37732 // ie requires a double layout on the first pass
37733 if(Roo.isIE && !this.initialized){
37734 this.initialized = true;
37735 this.layout.layout();
37740 // activate all subpanels if not currently active..
37742 setActiveState : function(active){
37743 this.active = active;
37744 this.setActiveClass(active);
37747 this.fireEvent("deactivate", this);
37751 this.fireEvent("activate", this);
37752 // not sure if this should happen before or after..
37753 if (!this.layout) {
37754 return; // should not happen..
37757 for (var r in this.layout.regions) {
37758 reg = this.layout.getRegion(r);
37759 if (reg.getActivePanel()) {
37760 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37761 reg.setActivePanel(reg.getActivePanel());
37764 if (!reg.panels.length) {
37767 reg.showPanel(reg.getPanel(0));
37776 * Returns the nested BorderLayout for this panel
37777 * @return {Roo.BorderLayout}
37779 getLayout : function(){
37780 return this.layout;
37784 * Adds a xtype elements to the layout of the nested panel
37788 xtype : 'ContentPanel',
37795 xtype : 'NestedLayoutPanel',
37801 items : [ ... list of content panels or nested layout panels.. ]
37805 * @param {Object} cfg Xtype definition of item to add.
37807 addxtype : function(cfg) {
37808 return this.layout.addxtype(cfg);
37813 * Ext JS Library 1.1.1
37814 * Copyright(c) 2006-2007, Ext JS, LLC.
37816 * Originally Released Under LGPL - original licence link has changed is not relivant.
37819 * <script type="text/javascript">
37822 * @class Roo.TabPanel
37823 * @extends Roo.util.Observable
37824 * A lightweight tab container.
37828 // basic tabs 1, built from existing content
37829 var tabs = new Roo.TabPanel("tabs1");
37830 tabs.addTab("script", "View Script");
37831 tabs.addTab("markup", "View Markup");
37832 tabs.activate("script");
37834 // more advanced tabs, built from javascript
37835 var jtabs = new Roo.TabPanel("jtabs");
37836 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37838 // set up the UpdateManager
37839 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37840 var updater = tab2.getUpdateManager();
37841 updater.setDefaultUrl("ajax1.htm");
37842 tab2.on('activate', updater.refresh, updater, true);
37844 // Use setUrl for Ajax loading
37845 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37846 tab3.setUrl("ajax2.htm", null, true);
37849 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37852 jtabs.activate("jtabs-1");
37855 * Create a new TabPanel.
37856 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37857 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37859 Roo.bootstrap.panel.Tabs = function(config){
37861 * The container element for this TabPanel.
37862 * @type Roo.Element
37864 this.el = Roo.get(config.el);
37867 if(typeof config == "boolean"){
37868 this.tabPosition = config ? "bottom" : "top";
37870 Roo.apply(this, config);
37874 if(this.tabPosition == "bottom"){
37875 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37876 this.el.addClass("roo-tabs-bottom");
37878 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37879 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37880 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37882 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37884 if(this.tabPosition != "bottom"){
37885 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37886 * @type Roo.Element
37888 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37889 this.el.addClass("roo-tabs-top");
37893 this.bodyEl.setStyle("position", "relative");
37895 this.active = null;
37896 this.activateDelegate = this.activate.createDelegate(this);
37901 * Fires when the active tab changes
37902 * @param {Roo.TabPanel} this
37903 * @param {Roo.TabPanelItem} activePanel The new active tab
37907 * @event beforetabchange
37908 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37909 * @param {Roo.TabPanel} this
37910 * @param {Object} e Set cancel to true on this object to cancel the tab change
37911 * @param {Roo.TabPanelItem} tab The tab being changed to
37913 "beforetabchange" : true
37916 Roo.EventManager.onWindowResize(this.onResize, this);
37917 this.cpad = this.el.getPadding("lr");
37918 this.hiddenCount = 0;
37921 // toolbar on the tabbar support...
37922 if (this.toolbar) {
37923 alert("no toolbar support yet");
37924 this.toolbar = false;
37926 var tcfg = this.toolbar;
37927 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37928 this.toolbar = new Roo.Toolbar(tcfg);
37929 if (Roo.isSafari) {
37930 var tbl = tcfg.container.child('table', true);
37931 tbl.setAttribute('width', '100%');
37939 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37942 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37944 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37946 tabPosition : "top",
37948 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37950 currentTabWidth : 0,
37952 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37956 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37960 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37962 preferredTabWidth : 175,
37964 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37966 resizeTabs : false,
37968 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37970 monitorResize : true,
37972 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37977 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37978 * @param {String} id The id of the div to use <b>or create</b>
37979 * @param {String} text The text for the tab
37980 * @param {String} content (optional) Content to put in the TabPanelItem body
37981 * @param {Boolean} closable (optional) True to create a close icon on the tab
37982 * @return {Roo.TabPanelItem} The created TabPanelItem
37984 addTab : function(id, text, content, closable, tpl)
37986 var item = new Roo.bootstrap.panel.TabItem({
37990 closable : closable,
37993 this.addTabItem(item);
37995 item.setContent(content);
38001 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38002 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38003 * @return {Roo.TabPanelItem}
38005 getTab : function(id){
38006 return this.items[id];
38010 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38011 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38013 hideTab : function(id){
38014 var t = this.items[id];
38017 this.hiddenCount++;
38018 this.autoSizeTabs();
38023 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38024 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38026 unhideTab : function(id){
38027 var t = this.items[id];
38029 t.setHidden(false);
38030 this.hiddenCount--;
38031 this.autoSizeTabs();
38036 * Adds an existing {@link Roo.TabPanelItem}.
38037 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38039 addTabItem : function(item){
38040 this.items[item.id] = item;
38041 this.items.push(item);
38042 // if(this.resizeTabs){
38043 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38044 // this.autoSizeTabs();
38046 // item.autoSize();
38051 * Removes a {@link Roo.TabPanelItem}.
38052 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38054 removeTab : function(id){
38055 var items = this.items;
38056 var tab = items[id];
38057 if(!tab) { return; }
38058 var index = items.indexOf(tab);
38059 if(this.active == tab && items.length > 1){
38060 var newTab = this.getNextAvailable(index);
38065 this.stripEl.dom.removeChild(tab.pnode.dom);
38066 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38067 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38069 items.splice(index, 1);
38070 delete this.items[tab.id];
38071 tab.fireEvent("close", tab);
38072 tab.purgeListeners();
38073 this.autoSizeTabs();
38076 getNextAvailable : function(start){
38077 var items = this.items;
38079 // look for a next tab that will slide over to
38080 // replace the one being removed
38081 while(index < items.length){
38082 var item = items[++index];
38083 if(item && !item.isHidden()){
38087 // if one isn't found select the previous tab (on the left)
38090 var item = items[--index];
38091 if(item && !item.isHidden()){
38099 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38100 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38102 disableTab : function(id){
38103 var tab = this.items[id];
38104 if(tab && this.active != tab){
38110 * Enables a {@link Roo.TabPanelItem} that is disabled.
38111 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38113 enableTab : function(id){
38114 var tab = this.items[id];
38119 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38120 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38121 * @return {Roo.TabPanelItem} The TabPanelItem.
38123 activate : function(id){
38124 var tab = this.items[id];
38128 if(tab == this.active || tab.disabled){
38132 this.fireEvent("beforetabchange", this, e, tab);
38133 if(e.cancel !== true && !tab.disabled){
38135 this.active.hide();
38137 this.active = this.items[id];
38138 this.active.show();
38139 this.fireEvent("tabchange", this, this.active);
38145 * Gets the active {@link Roo.TabPanelItem}.
38146 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38148 getActiveTab : function(){
38149 return this.active;
38153 * Updates the tab body element to fit the height of the container element
38154 * for overflow scrolling
38155 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38157 syncHeight : function(targetHeight){
38158 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38159 var bm = this.bodyEl.getMargins();
38160 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38161 this.bodyEl.setHeight(newHeight);
38165 onResize : function(){
38166 if(this.monitorResize){
38167 this.autoSizeTabs();
38172 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38174 beginUpdate : function(){
38175 this.updating = true;
38179 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38181 endUpdate : function(){
38182 this.updating = false;
38183 this.autoSizeTabs();
38187 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38189 autoSizeTabs : function(){
38190 var count = this.items.length;
38191 var vcount = count - this.hiddenCount;
38192 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38195 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38196 var availWidth = Math.floor(w / vcount);
38197 var b = this.stripBody;
38198 if(b.getWidth() > w){
38199 var tabs = this.items;
38200 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38201 if(availWidth < this.minTabWidth){
38202 /*if(!this.sleft){ // incomplete scrolling code
38203 this.createScrollButtons();
38206 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38209 if(this.currentTabWidth < this.preferredTabWidth){
38210 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38216 * Returns the number of tabs in this TabPanel.
38219 getCount : function(){
38220 return this.items.length;
38224 * Resizes all the tabs to the passed width
38225 * @param {Number} The new width
38227 setTabWidth : function(width){
38228 this.currentTabWidth = width;
38229 for(var i = 0, len = this.items.length; i < len; i++) {
38230 if(!this.items[i].isHidden()) {
38231 this.items[i].setWidth(width);
38237 * Destroys this TabPanel
38238 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38240 destroy : function(removeEl){
38241 Roo.EventManager.removeResizeListener(this.onResize, this);
38242 for(var i = 0, len = this.items.length; i < len; i++){
38243 this.items[i].purgeListeners();
38245 if(removeEl === true){
38246 this.el.update("");
38251 createStrip : function(container)
38253 var strip = document.createElement("nav");
38254 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38255 container.appendChild(strip);
38259 createStripList : function(strip)
38261 // div wrapper for retard IE
38262 // returns the "tr" element.
38263 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38264 //'<div class="x-tabs-strip-wrap">'+
38265 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38266 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38267 return strip.firstChild; //.firstChild.firstChild.firstChild;
38269 createBody : function(container)
38271 var body = document.createElement("div");
38272 Roo.id(body, "tab-body");
38273 //Roo.fly(body).addClass("x-tabs-body");
38274 Roo.fly(body).addClass("tab-content");
38275 container.appendChild(body);
38278 createItemBody :function(bodyEl, id){
38279 var body = Roo.getDom(id);
38281 body = document.createElement("div");
38284 //Roo.fly(body).addClass("x-tabs-item-body");
38285 Roo.fly(body).addClass("tab-pane");
38286 bodyEl.insertBefore(body, bodyEl.firstChild);
38290 createStripElements : function(stripEl, text, closable, tpl)
38292 var td = document.createElement("li"); // was td..
38295 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38298 stripEl.appendChild(td);
38300 td.className = "x-tabs-closable";
38301 if(!this.closeTpl){
38302 this.closeTpl = new Roo.Template(
38303 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38304 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38305 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38308 var el = this.closeTpl.overwrite(td, {"text": text});
38309 var close = el.getElementsByTagName("div")[0];
38310 var inner = el.getElementsByTagName("em")[0];
38311 return {"el": el, "close": close, "inner": inner};
38314 // not sure what this is..
38315 // if(!this.tabTpl){
38316 //this.tabTpl = new Roo.Template(
38317 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38318 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38320 // this.tabTpl = new Roo.Template(
38321 // '<a href="#">' +
38322 // '<span unselectable="on"' +
38323 // (this.disableTooltips ? '' : ' title="{text}"') +
38324 // ' >{text}</span></a>'
38330 var template = tpl || this.tabTpl || false;
38334 template = new Roo.Template(
38336 '<span unselectable="on"' +
38337 (this.disableTooltips ? '' : ' title="{text}"') +
38338 ' >{text}</span></a>'
38342 switch (typeof(template)) {
38346 template = new Roo.Template(template);
38352 var el = template.overwrite(td, {"text": text});
38354 var inner = el.getElementsByTagName("span")[0];
38356 return {"el": el, "inner": inner};
38364 * @class Roo.TabPanelItem
38365 * @extends Roo.util.Observable
38366 * Represents an individual item (tab plus body) in a TabPanel.
38367 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38368 * @param {String} id The id of this TabPanelItem
38369 * @param {String} text The text for the tab of this TabPanelItem
38370 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38372 Roo.bootstrap.panel.TabItem = function(config){
38374 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38375 * @type Roo.TabPanel
38377 this.tabPanel = config.panel;
38379 * The id for this TabPanelItem
38382 this.id = config.id;
38384 this.disabled = false;
38386 this.text = config.text;
38388 this.loaded = false;
38389 this.closable = config.closable;
38392 * The body element for this TabPanelItem.
38393 * @type Roo.Element
38395 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38396 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38397 this.bodyEl.setStyle("display", "block");
38398 this.bodyEl.setStyle("zoom", "1");
38399 //this.hideAction();
38401 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38403 this.el = Roo.get(els.el);
38404 this.inner = Roo.get(els.inner, true);
38405 this.textEl = Roo.get(this.el.dom.firstChild, true);
38406 this.pnode = Roo.get(els.el.parentNode, true);
38407 // this.el.on("mousedown", this.onTabMouseDown, this);
38408 this.el.on("click", this.onTabClick, this);
38410 if(config.closable){
38411 var c = Roo.get(els.close, true);
38412 c.dom.title = this.closeText;
38413 c.addClassOnOver("close-over");
38414 c.on("click", this.closeClick, this);
38420 * Fires when this tab becomes the active tab.
38421 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38422 * @param {Roo.TabPanelItem} this
38426 * @event beforeclose
38427 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38428 * @param {Roo.TabPanelItem} this
38429 * @param {Object} e Set cancel to true on this object to cancel the close.
38431 "beforeclose": true,
38434 * Fires when this tab is closed.
38435 * @param {Roo.TabPanelItem} this
38439 * @event deactivate
38440 * Fires when this tab is no longer the active tab.
38441 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38442 * @param {Roo.TabPanelItem} this
38444 "deactivate" : true
38446 this.hidden = false;
38448 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38451 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38453 purgeListeners : function(){
38454 Roo.util.Observable.prototype.purgeListeners.call(this);
38455 this.el.removeAllListeners();
38458 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38461 this.pnode.addClass("active");
38464 this.tabPanel.stripWrap.repaint();
38466 this.fireEvent("activate", this.tabPanel, this);
38470 * Returns true if this tab is the active tab.
38471 * @return {Boolean}
38473 isActive : function(){
38474 return this.tabPanel.getActiveTab() == this;
38478 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38481 this.pnode.removeClass("active");
38483 this.fireEvent("deactivate", this.tabPanel, this);
38486 hideAction : function(){
38487 this.bodyEl.hide();
38488 this.bodyEl.setStyle("position", "absolute");
38489 this.bodyEl.setLeft("-20000px");
38490 this.bodyEl.setTop("-20000px");
38493 showAction : function(){
38494 this.bodyEl.setStyle("position", "relative");
38495 this.bodyEl.setTop("");
38496 this.bodyEl.setLeft("");
38497 this.bodyEl.show();
38501 * Set the tooltip for the tab.
38502 * @param {String} tooltip The tab's tooltip
38504 setTooltip : function(text){
38505 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38506 this.textEl.dom.qtip = text;
38507 this.textEl.dom.removeAttribute('title');
38509 this.textEl.dom.title = text;
38513 onTabClick : function(e){
38514 e.preventDefault();
38515 this.tabPanel.activate(this.id);
38518 onTabMouseDown : function(e){
38519 e.preventDefault();
38520 this.tabPanel.activate(this.id);
38523 getWidth : function(){
38524 return this.inner.getWidth();
38527 setWidth : function(width){
38528 var iwidth = width - this.pnode.getPadding("lr");
38529 this.inner.setWidth(iwidth);
38530 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38531 this.pnode.setWidth(width);
38535 * Show or hide the tab
38536 * @param {Boolean} hidden True to hide or false to show.
38538 setHidden : function(hidden){
38539 this.hidden = hidden;
38540 this.pnode.setStyle("display", hidden ? "none" : "");
38544 * Returns true if this tab is "hidden"
38545 * @return {Boolean}
38547 isHidden : function(){
38548 return this.hidden;
38552 * Returns the text for this tab
38555 getText : function(){
38559 autoSize : function(){
38560 //this.el.beginMeasure();
38561 this.textEl.setWidth(1);
38563 * #2804 [new] Tabs in Roojs
38564 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38566 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38567 //this.el.endMeasure();
38571 * Sets the text for the tab (Note: this also sets the tooltip text)
38572 * @param {String} text The tab's text and tooltip
38574 setText : function(text){
38576 this.textEl.update(text);
38577 this.setTooltip(text);
38578 //if(!this.tabPanel.resizeTabs){
38579 // this.autoSize();
38583 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38585 activate : function(){
38586 this.tabPanel.activate(this.id);
38590 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38592 disable : function(){
38593 if(this.tabPanel.active != this){
38594 this.disabled = true;
38595 this.pnode.addClass("disabled");
38600 * Enables this TabPanelItem if it was previously disabled.
38602 enable : function(){
38603 this.disabled = false;
38604 this.pnode.removeClass("disabled");
38608 * Sets the content for this TabPanelItem.
38609 * @param {String} content The content
38610 * @param {Boolean} loadScripts true to look for and load scripts
38612 setContent : function(content, loadScripts){
38613 this.bodyEl.update(content, loadScripts);
38617 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38618 * @return {Roo.UpdateManager} The UpdateManager
38620 getUpdateManager : function(){
38621 return this.bodyEl.getUpdateManager();
38625 * Set a URL to be used to load the content for this TabPanelItem.
38626 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38627 * @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)
38628 * @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)
38629 * @return {Roo.UpdateManager} The UpdateManager
38631 setUrl : function(url, params, loadOnce){
38632 if(this.refreshDelegate){
38633 this.un('activate', this.refreshDelegate);
38635 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38636 this.on("activate", this.refreshDelegate);
38637 return this.bodyEl.getUpdateManager();
38641 _handleRefresh : function(url, params, loadOnce){
38642 if(!loadOnce || !this.loaded){
38643 var updater = this.bodyEl.getUpdateManager();
38644 updater.update(url, params, this._setLoaded.createDelegate(this));
38649 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38650 * Will fail silently if the setUrl method has not been called.
38651 * This does not activate the panel, just updates its content.
38653 refresh : function(){
38654 if(this.refreshDelegate){
38655 this.loaded = false;
38656 this.refreshDelegate();
38661 _setLoaded : function(){
38662 this.loaded = true;
38666 closeClick : function(e){
38669 this.fireEvent("beforeclose", this, o);
38670 if(o.cancel !== true){
38671 this.tabPanel.removeTab(this.id);
38675 * The text displayed in the tooltip for the close icon.
38678 closeText : "Close this tab"
38681 * This script refer to:
38682 * Title: International Telephone Input
38683 * Author: Jack O'Connor
38684 * Code version: v12.1.12
38685 * Availability: https://github.com/jackocnr/intl-tel-input.git
38688 Roo.bootstrap.PhoneInputData = function() {
38691 "Afghanistan (افغانستان)",
38696 "Albania (Shqipëri)",
38701 "Algeria (الجزائر)",
38726 "Antigua and Barbuda",
38736 "Armenia (Հայաստան)",
38752 "Austria (Österreich)",
38757 "Azerbaijan (Azərbaycan)",
38767 "Bahrain (البحرين)",
38772 "Bangladesh (বাংলাদেশ)",
38782 "Belarus (Беларусь)",
38787 "Belgium (België)",
38817 "Bosnia and Herzegovina (Босна и Херцеговина)",
38832 "British Indian Ocean Territory",
38837 "British Virgin Islands",
38847 "Bulgaria (България)",
38857 "Burundi (Uburundi)",
38862 "Cambodia (កម្ពុជា)",
38867 "Cameroon (Cameroun)",
38876 ["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"]
38879 "Cape Verde (Kabu Verdi)",
38884 "Caribbean Netherlands",
38895 "Central African Republic (République centrafricaine)",
38915 "Christmas Island",
38921 "Cocos (Keeling) Islands",
38932 "Comoros (جزر القمر)",
38937 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38942 "Congo (Republic) (Congo-Brazzaville)",
38962 "Croatia (Hrvatska)",
38983 "Czech Republic (Česká republika)",
38988 "Denmark (Danmark)",
39003 "Dominican Republic (República Dominicana)",
39007 ["809", "829", "849"]
39025 "Equatorial Guinea (Guinea Ecuatorial)",
39045 "Falkland Islands (Islas Malvinas)",
39050 "Faroe Islands (Føroyar)",
39071 "French Guiana (Guyane française)",
39076 "French Polynesia (Polynésie française)",
39091 "Georgia (საქართველო)",
39096 "Germany (Deutschland)",
39116 "Greenland (Kalaallit Nunaat)",
39153 "Guinea-Bissau (Guiné Bissau)",
39178 "Hungary (Magyarország)",
39183 "Iceland (Ísland)",
39203 "Iraq (العراق)",
39219 "Israel (ישראל)",
39246 "Jordan (الأردن)",
39251 "Kazakhstan (Казахстан)",
39272 "Kuwait (الكويت)",
39277 "Kyrgyzstan (Кыргызстан)",
39287 "Latvia (Latvija)",
39292 "Lebanon (لبنان)",
39307 "Libya (ليبيا)",
39317 "Lithuania (Lietuva)",
39332 "Macedonia (FYROM) (Македонија)",
39337 "Madagascar (Madagasikara)",
39367 "Marshall Islands",
39377 "Mauritania (موريتانيا)",
39382 "Mauritius (Moris)",
39403 "Moldova (Republica Moldova)",
39413 "Mongolia (Монгол)",
39418 "Montenegro (Crna Gora)",
39428 "Morocco (المغرب)",
39434 "Mozambique (Moçambique)",
39439 "Myanmar (Burma) (မြန်မာ)",
39444 "Namibia (Namibië)",
39459 "Netherlands (Nederland)",
39464 "New Caledonia (Nouvelle-Calédonie)",
39499 "North Korea (조선 민주주의 인민 공화국)",
39504 "Northern Mariana Islands",
39520 "Pakistan (پاکستان)",
39530 "Palestine (فلسطين)",
39540 "Papua New Guinea",
39582 "Réunion (La Réunion)",
39588 "Romania (România)",
39604 "Saint Barthélemy",
39615 "Saint Kitts and Nevis",
39625 "Saint Martin (Saint-Martin (partie française))",
39631 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39636 "Saint Vincent and the Grenadines",
39651 "São Tomé and Príncipe (São Tomé e Príncipe)",
39656 "Saudi Arabia (المملكة العربية السعودية)",
39661 "Senegal (Sénégal)",
39691 "Slovakia (Slovensko)",
39696 "Slovenia (Slovenija)",
39706 "Somalia (Soomaaliya)",
39716 "South Korea (대한민국)",
39721 "South Sudan (جنوب السودان)",
39731 "Sri Lanka (ශ්රී ලංකාව)",
39736 "Sudan (السودان)",
39746 "Svalbard and Jan Mayen",
39757 "Sweden (Sverige)",
39762 "Switzerland (Schweiz)",
39767 "Syria (سوريا)",
39812 "Trinidad and Tobago",
39817 "Tunisia (تونس)",
39822 "Turkey (Türkiye)",
39832 "Turks and Caicos Islands",
39842 "U.S. Virgin Islands",
39852 "Ukraine (Україна)",
39857 "United Arab Emirates (الإمارات العربية المتحدة)",
39879 "Uzbekistan (Oʻzbekiston)",
39889 "Vatican City (Città del Vaticano)",
39900 "Vietnam (Việt Nam)",
39905 "Wallis and Futuna (Wallis-et-Futuna)",
39910 "Western Sahara (الصحراء الغربية)",
39916 "Yemen (اليمن)",
39940 * This script refer to:
39941 * Title: International Telephone Input
39942 * Author: Jack O'Connor
39943 * Code version: v12.1.12
39944 * Availability: https://github.com/jackocnr/intl-tel-input.git
39948 * @class Roo.bootstrap.PhoneInput
39949 * @extends Roo.bootstrap.TriggerField
39950 * An input with International dial-code selection
39952 * @cfg {String} defaultDialCode default '+852'
39953 * @cfg {Array} preferedCountries default []
39956 * Create a new PhoneInput.
39957 * @param {Object} config Configuration options
39960 Roo.bootstrap.PhoneInput = function(config) {
39961 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39964 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39966 listWidth: undefined,
39968 selectedClass: 'active',
39970 invalidClass : "has-warning",
39972 validClass: 'has-success',
39974 allowed: '0123456789',
39979 * @cfg {String} defaultDialCode The default dial code when initializing the input
39981 defaultDialCode: '+852',
39984 * @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
39986 preferedCountries: false,
39988 getAutoCreate : function()
39990 var data = Roo.bootstrap.PhoneInputData();
39991 var align = this.labelAlign || this.parentLabelAlign();
39994 this.allCountries = [];
39995 this.dialCodeMapping = [];
39997 for (var i = 0; i < data.length; i++) {
39999 this.allCountries[i] = {
40003 priority: c[3] || 0,
40004 areaCodes: c[4] || null
40006 this.dialCodeMapping[c[2]] = {
40009 priority: c[3] || 0,
40010 areaCodes: c[4] || null
40022 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40023 maxlength: this.max_length,
40024 cls : 'form-control tel-input',
40025 autocomplete: 'new-password'
40028 var hiddenInput = {
40031 cls: 'hidden-tel-input'
40035 hiddenInput.name = this.name;
40038 if (this.disabled) {
40039 input.disabled = true;
40042 var flag_container = {
40059 cls: this.hasFeedback ? 'has-feedback' : '',
40065 cls: 'dial-code-holder',
40072 cls: 'roo-select2-container input-group',
40079 if (this.fieldLabel.length) {
40082 tooltip: 'This field is required'
40088 cls: 'control-label',
40094 html: this.fieldLabel
40097 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40103 if(this.indicatorpos == 'right') {
40104 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40111 if(align == 'left') {
40119 if(this.labelWidth > 12){
40120 label.style = "width: " + this.labelWidth + 'px';
40122 if(this.labelWidth < 13 && this.labelmd == 0){
40123 this.labelmd = this.labelWidth;
40125 if(this.labellg > 0){
40126 label.cls += ' col-lg-' + this.labellg;
40127 input.cls += ' col-lg-' + (12 - this.labellg);
40129 if(this.labelmd > 0){
40130 label.cls += ' col-md-' + this.labelmd;
40131 container.cls += ' col-md-' + (12 - this.labelmd);
40133 if(this.labelsm > 0){
40134 label.cls += ' col-sm-' + this.labelsm;
40135 container.cls += ' col-sm-' + (12 - this.labelsm);
40137 if(this.labelxs > 0){
40138 label.cls += ' col-xs-' + this.labelxs;
40139 container.cls += ' col-xs-' + (12 - this.labelxs);
40149 var settings = this;
40151 ['xs','sm','md','lg'].map(function(size){
40152 if (settings[size]) {
40153 cfg.cls += ' col-' + size + '-' + settings[size];
40157 this.store = new Roo.data.Store({
40158 proxy : new Roo.data.MemoryProxy({}),
40159 reader : new Roo.data.JsonReader({
40170 'name' : 'dialCode',
40174 'name' : 'priority',
40178 'name' : 'areaCodes',
40185 if(!this.preferedCountries) {
40186 this.preferedCountries = [
40193 var p = this.preferedCountries.reverse();
40196 for (var i = 0; i < p.length; i++) {
40197 for (var j = 0; j < this.allCountries.length; j++) {
40198 if(this.allCountries[j].iso2 == p[i]) {
40199 var t = this.allCountries[j];
40200 this.allCountries.splice(j,1);
40201 this.allCountries.unshift(t);
40207 this.store.proxy.data = {
40209 data: this.allCountries
40215 initEvents : function()
40218 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40220 this.indicator = this.indicatorEl();
40221 this.flag = this.flagEl();
40222 this.dialCodeHolder = this.dialCodeHolderEl();
40224 this.trigger = this.el.select('div.flag-box',true).first();
40225 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40230 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40231 _this.list.setWidth(lw);
40234 this.list.on('mouseover', this.onViewOver, this);
40235 this.list.on('mousemove', this.onViewMove, this);
40236 this.inputEl().on("keyup", this.onKeyUp, this);
40237 this.inputEl().on("keypress", this.onKeyPress, this);
40239 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40241 this.view = new Roo.View(this.list, this.tpl, {
40242 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40245 this.view.on('click', this.onViewClick, this);
40246 this.setValue(this.defaultDialCode);
40249 onTriggerClick : function(e)
40251 Roo.log('trigger click');
40256 if(this.isExpanded()){
40258 this.hasFocus = false;
40260 this.store.load({});
40261 this.hasFocus = true;
40266 isExpanded : function()
40268 return this.list.isVisible();
40271 collapse : function()
40273 if(!this.isExpanded()){
40277 Roo.get(document).un('mousedown', this.collapseIf, this);
40278 Roo.get(document).un('mousewheel', this.collapseIf, this);
40279 this.fireEvent('collapse', this);
40283 expand : function()
40287 if(this.isExpanded() || !this.hasFocus){
40291 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40292 this.list.setWidth(lw);
40295 this.restrictHeight();
40297 Roo.get(document).on('mousedown', this.collapseIf, this);
40298 Roo.get(document).on('mousewheel', this.collapseIf, this);
40300 this.fireEvent('expand', this);
40303 restrictHeight : function()
40305 this.list.alignTo(this.inputEl(), this.listAlign);
40306 this.list.alignTo(this.inputEl(), this.listAlign);
40309 onViewOver : function(e, t)
40311 if(this.inKeyMode){
40314 var item = this.view.findItemFromChild(t);
40317 var index = this.view.indexOf(item);
40318 this.select(index, false);
40323 onViewClick : function(view, doFocus, el, e)
40325 var index = this.view.getSelectedIndexes()[0];
40327 var r = this.store.getAt(index);
40330 this.onSelect(r, index);
40332 if(doFocus !== false && !this.blockFocus){
40333 this.inputEl().focus();
40337 onViewMove : function(e, t)
40339 this.inKeyMode = false;
40342 select : function(index, scrollIntoView)
40344 this.selectedIndex = index;
40345 this.view.select(index);
40346 if(scrollIntoView !== false){
40347 var el = this.view.getNode(index);
40349 this.list.scrollChildIntoView(el, false);
40354 createList : function()
40356 this.list = Roo.get(document.body).createChild({
40358 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40359 style: 'display:none'
40362 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40365 collapseIf : function(e)
40367 var in_combo = e.within(this.el);
40368 var in_list = e.within(this.list);
40369 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40371 if (in_combo || in_list || is_list) {
40377 onSelect : function(record, index)
40379 if(this.fireEvent('beforeselect', this, record, index) !== false){
40381 this.setFlagClass(record.data.iso2);
40382 this.setDialCode(record.data.dialCode);
40383 this.hasFocus = false;
40385 this.fireEvent('select', this, record, index);
40389 flagEl : function()
40391 var flag = this.el.select('div.flag',true).first();
40398 dialCodeHolderEl : function()
40400 var d = this.el.select('input.dial-code-holder',true).first();
40407 setDialCode : function(v)
40409 this.dialCodeHolder.dom.value = '+'+v;
40412 setFlagClass : function(n)
40414 this.flag.dom.className = 'flag '+n;
40417 getValue : function()
40419 var v = this.inputEl().getValue();
40420 if(this.dialCodeHolder) {
40421 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40426 setValue : function(v)
40428 var d = this.getDialCode(v);
40430 //invalid dial code
40431 if(v.length == 0 || !d || d.length == 0) {
40433 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40434 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40440 this.setFlagClass(this.dialCodeMapping[d].iso2);
40441 this.setDialCode(d);
40442 this.inputEl().dom.value = v.replace('+'+d,'');
40443 this.hiddenEl().dom.value = this.getValue();
40448 getDialCode : function(v)
40452 if (v.length == 0) {
40453 return this.dialCodeHolder.dom.value;
40457 if (v.charAt(0) != "+") {
40460 var numericChars = "";
40461 for (var i = 1; i < v.length; i++) {
40462 var c = v.charAt(i);
40465 if (this.dialCodeMapping[numericChars]) {
40466 dialCode = v.substr(1, i);
40468 if (numericChars.length == 4) {
40478 this.setValue(this.defaultDialCode);
40482 hiddenEl : function()
40484 return this.el.select('input.hidden-tel-input',true).first();
40487 // after setting val
40488 onKeyUp : function(e){
40489 this.setValue(this.getValue());
40492 onKeyPress : function(e){
40493 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40500 * @class Roo.bootstrap.MoneyField
40501 * @extends Roo.bootstrap.ComboBox
40502 * Bootstrap MoneyField class
40505 * Create a new MoneyField.
40506 * @param {Object} config Configuration options
40509 Roo.bootstrap.MoneyField = function(config) {
40511 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40515 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40518 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40520 allowDecimals : true,
40522 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40524 decimalSeparator : ".",
40526 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40528 decimalPrecision : 0,
40530 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40532 allowNegative : true,
40534 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40538 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40540 minValue : Number.NEGATIVE_INFINITY,
40542 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40544 maxValue : Number.MAX_VALUE,
40546 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40548 minText : "The minimum value for this field is {0}",
40550 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40552 maxText : "The maximum value for this field is {0}",
40554 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40555 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40557 nanText : "{0} is not a valid number",
40559 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40563 * @cfg {String} defaults currency of the MoneyField
40564 * value should be in lkey
40566 defaultCurrency : false,
40568 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40570 thousandsDelimiter : false,
40572 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40583 getAutoCreate : function()
40585 var align = this.labelAlign || this.parentLabelAlign();
40597 cls : 'form-control roo-money-amount-input',
40598 autocomplete: 'new-password'
40601 var hiddenInput = {
40605 cls: 'hidden-number-input'
40608 if(this.max_length) {
40609 input.maxlength = this.max_length;
40613 hiddenInput.name = this.name;
40616 if (this.disabled) {
40617 input.disabled = true;
40620 var clg = 12 - this.inputlg;
40621 var cmd = 12 - this.inputmd;
40622 var csm = 12 - this.inputsm;
40623 var cxs = 12 - this.inputxs;
40627 cls : 'row roo-money-field',
40631 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40635 cls: 'roo-select2-container input-group',
40639 cls : 'form-control roo-money-currency-input',
40640 autocomplete: 'new-password',
40642 name : this.currencyName
40646 cls : 'input-group-addon',
40660 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40664 cls: this.hasFeedback ? 'has-feedback' : '',
40675 if (this.fieldLabel.length) {
40678 tooltip: 'This field is required'
40684 cls: 'control-label',
40690 html: this.fieldLabel
40693 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40699 if(this.indicatorpos == 'right') {
40700 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40707 if(align == 'left') {
40715 if(this.labelWidth > 12){
40716 label.style = "width: " + this.labelWidth + 'px';
40718 if(this.labelWidth < 13 && this.labelmd == 0){
40719 this.labelmd = this.labelWidth;
40721 if(this.labellg > 0){
40722 label.cls += ' col-lg-' + this.labellg;
40723 input.cls += ' col-lg-' + (12 - this.labellg);
40725 if(this.labelmd > 0){
40726 label.cls += ' col-md-' + this.labelmd;
40727 container.cls += ' col-md-' + (12 - this.labelmd);
40729 if(this.labelsm > 0){
40730 label.cls += ' col-sm-' + this.labelsm;
40731 container.cls += ' col-sm-' + (12 - this.labelsm);
40733 if(this.labelxs > 0){
40734 label.cls += ' col-xs-' + this.labelxs;
40735 container.cls += ' col-xs-' + (12 - this.labelxs);
40746 var settings = this;
40748 ['xs','sm','md','lg'].map(function(size){
40749 if (settings[size]) {
40750 cfg.cls += ' col-' + size + '-' + settings[size];
40757 initEvents : function()
40759 this.indicator = this.indicatorEl();
40761 this.initCurrencyEvent();
40763 this.initNumberEvent();
40766 initCurrencyEvent : function()
40769 throw "can not find store for combo";
40772 this.store = Roo.factory(this.store, Roo.data);
40773 this.store.parent = this;
40777 this.triggerEl = this.el.select('.input-group-addon', true).first();
40779 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40784 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40785 _this.list.setWidth(lw);
40788 this.list.on('mouseover', this.onViewOver, this);
40789 this.list.on('mousemove', this.onViewMove, this);
40790 this.list.on('scroll', this.onViewScroll, this);
40793 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40796 this.view = new Roo.View(this.list, this.tpl, {
40797 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40800 this.view.on('click', this.onViewClick, this);
40802 this.store.on('beforeload', this.onBeforeLoad, this);
40803 this.store.on('load', this.onLoad, this);
40804 this.store.on('loadexception', this.onLoadException, this);
40806 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40807 "up" : function(e){
40808 this.inKeyMode = true;
40812 "down" : function(e){
40813 if(!this.isExpanded()){
40814 this.onTriggerClick();
40816 this.inKeyMode = true;
40821 "enter" : function(e){
40824 if(this.fireEvent("specialkey", this, e)){
40825 this.onViewClick(false);
40831 "esc" : function(e){
40835 "tab" : function(e){
40838 if(this.fireEvent("specialkey", this, e)){
40839 this.onViewClick(false);
40847 doRelay : function(foo, bar, hname){
40848 if(hname == 'down' || this.scope.isExpanded()){
40849 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40857 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40861 initNumberEvent : function(e)
40863 this.inputEl().on("keydown" , this.fireKey, this);
40864 this.inputEl().on("focus", this.onFocus, this);
40865 this.inputEl().on("blur", this.onBlur, this);
40867 this.inputEl().relayEvent('keyup', this);
40869 if(this.indicator){
40870 this.indicator.addClass('invisible');
40873 this.originalValue = this.getValue();
40875 if(this.validationEvent == 'keyup'){
40876 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40877 this.inputEl().on('keyup', this.filterValidation, this);
40879 else if(this.validationEvent !== false){
40880 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40883 if(this.selectOnFocus){
40884 this.on("focus", this.preFocus, this);
40887 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40888 this.inputEl().on("keypress", this.filterKeys, this);
40890 this.inputEl().relayEvent('keypress', this);
40893 var allowed = "0123456789";
40895 if(this.allowDecimals){
40896 allowed += this.decimalSeparator;
40899 if(this.allowNegative){
40903 if(this.thousandsDelimiter) {
40907 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40909 var keyPress = function(e){
40911 var k = e.getKey();
40913 var c = e.getCharCode();
40916 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40917 allowed.indexOf(String.fromCharCode(c)) === -1
40923 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40927 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40932 this.inputEl().on("keypress", keyPress, this);
40936 onTriggerClick : function(e)
40943 this.loadNext = false;
40945 if(this.isExpanded()){
40950 this.hasFocus = true;
40952 if(this.triggerAction == 'all') {
40953 this.doQuery(this.allQuery, true);
40957 this.doQuery(this.getRawValue());
40960 getCurrency : function()
40962 var v = this.currencyEl().getValue();
40967 restrictHeight : function()
40969 this.list.alignTo(this.currencyEl(), this.listAlign);
40970 this.list.alignTo(this.currencyEl(), this.listAlign);
40973 onViewClick : function(view, doFocus, el, e)
40975 var index = this.view.getSelectedIndexes()[0];
40977 var r = this.store.getAt(index);
40980 this.onSelect(r, index);
40984 onSelect : function(record, index){
40986 if(this.fireEvent('beforeselect', this, record, index) !== false){
40988 this.setFromCurrencyData(index > -1 ? record.data : false);
40992 this.fireEvent('select', this, record, index);
40996 setFromCurrencyData : function(o)
41000 this.lastCurrency = o;
41002 if (this.currencyField) {
41003 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41005 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41008 this.lastSelectionText = currency;
41010 //setting default currency
41011 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41012 this.setCurrency(this.defaultCurrency);
41016 this.setCurrency(currency);
41019 setFromData : function(o)
41023 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41025 this.setFromCurrencyData(c);
41030 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41032 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41035 this.setValue(value);
41039 setCurrency : function(v)
41041 this.currencyValue = v;
41044 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41049 setValue : function(v)
41051 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41057 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41059 this.inputEl().dom.value = (v == '') ? '' :
41060 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41062 if(!this.allowZero && v === '0') {
41063 this.hiddenEl().dom.value = '';
41064 this.inputEl().dom.value = '';
41071 getRawValue : function()
41073 var v = this.inputEl().getValue();
41078 getValue : function()
41080 return this.fixPrecision(this.parseValue(this.getRawValue()));
41083 parseValue : function(value)
41085 if(this.thousandsDelimiter) {
41087 r = new RegExp(",", "g");
41088 value = value.replace(r, "");
41091 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41092 return isNaN(value) ? '' : value;
41096 fixPrecision : function(value)
41098 if(this.thousandsDelimiter) {
41100 r = new RegExp(",", "g");
41101 value = value.replace(r, "");
41104 var nan = isNaN(value);
41106 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41107 return nan ? '' : value;
41109 return parseFloat(value).toFixed(this.decimalPrecision);
41112 decimalPrecisionFcn : function(v)
41114 return Math.floor(v);
41117 validateValue : function(value)
41119 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41123 var num = this.parseValue(value);
41126 this.markInvalid(String.format(this.nanText, value));
41130 if(num < this.minValue){
41131 this.markInvalid(String.format(this.minText, this.minValue));
41135 if(num > this.maxValue){
41136 this.markInvalid(String.format(this.maxText, this.maxValue));
41143 validate : function()
41145 if(this.disabled || this.allowBlank){
41150 var currency = this.getCurrency();
41152 if(this.validateValue(this.getRawValue()) && currency.length){
41157 this.markInvalid();
41161 getName: function()
41166 beforeBlur : function()
41172 var v = this.parseValue(this.getRawValue());
41179 onBlur : function()
41183 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41184 //this.el.removeClass(this.focusClass);
41187 this.hasFocus = false;
41189 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41193 var v = this.getValue();
41195 if(String(v) !== String(this.startValue)){
41196 this.fireEvent('change', this, v, this.startValue);
41199 this.fireEvent("blur", this);
41202 inputEl : function()
41204 return this.el.select('.roo-money-amount-input', true).first();
41207 currencyEl : function()
41209 return this.el.select('.roo-money-currency-input', true).first();
41212 hiddenEl : function()
41214 return this.el.select('input.hidden-number-input',true).first();